diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
commit | dc0db358abe19481e475e10c32149b53370f1a1c (patch) | |
tree | ab8ce99c4b255ce46f99ef402c27916055b899ee /compiler/rustc_hir_analysis | |
parent | Releasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip |
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis')
36 files changed, 2620 insertions, 2010 deletions
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 02d1dfcd1..166760166 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -99,6 +99,15 @@ hir_analysis_invalid_union_field = hir_analysis_invalid_union_field_sugg = wrap the field type in `ManuallyDrop<...>` +hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl + .label = const parameter declared here + +hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetimes from an fn or impl + .label = lifetime declared here + +hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl + .label = type parameter declared here + hir_analysis_lifetimes_or_bounds_mismatch_on_trait = lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration .label = lifetimes do not match {$item_kind} in trait @@ -137,7 +146,7 @@ hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snip hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}` .note = default implementation of `{$missing_item_name}` is unstable - .some_note = use of unstable library feature '{$feature}': {$r} + .some_note = use of unstable library feature '{$feature}': {$reason} .none_note = use of unstable library feature '{$feature}' hir_analysis_missing_type_params = @@ -195,6 +204,13 @@ hir_analysis_return_type_notation_conflicting_bound = hir_analysis_return_type_notation_equality_bound = return type notation is not allowed to use type equality +hir_analysis_return_type_notation_illegal_param_const = + return type notation is not allowed for functions that have const parameters + .label = const parameter declared here +hir_analysis_return_type_notation_illegal_param_type = + return type notation is not allowed for functions that have type parameters + .label = type parameter declared here + hir_analysis_return_type_notation_missing_method = cannot find associated function `{$assoc_name}` for `{$ty_name}` @@ -232,6 +248,9 @@ hir_analysis_static_specialize = cannot specialize on `'static` lifetime hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl +hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature + .note = this item must mention the opaque type in its signature in order to be able to register hidden types + hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]` hir_analysis_too_large_static = extern static is too large for the current architecture @@ -272,6 +291,11 @@ hir_analysis_unrecognized_intrinsic_function = unrecognized intrinsic function: `{$name}` .label = unrecognized intrinsic +hir_analysis_unused_associated_type_bounds = + unnecessary associated type bound for not object safe associated type + .note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + .suggestion = remove this bound + hir_analysis_value_of_associated_struct_already_specified = the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified .label = re-bound here diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs new file mode 100644 index 000000000..b13de7701 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -0,0 +1,575 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_lint_defs::Applicability; +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 crate::astconv::{ + AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter, +}; +use crate::bounds::Bounds; +use crate::errors::{MultipleRelaxedDefaultBounds, ValueOfAssociatedStructAlreadySpecified}; + +impl<'tcx> dyn AstConv<'tcx> + '_ { + /// Sets `implicitly_sized` to true on `Bounds` if necessary + pub(crate) fn add_implicitly_sized( + &self, + bounds: &mut Bounds<'tcx>, + self_ty: Ty<'tcx>, + ast_bounds: &'tcx [hir::GenericBound<'tcx>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + span: Span, + ) { + let tcx = self.tcx(); + + // Try to find an unbound in bounds. + let mut unbound = None; + 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(MultipleRelaxedDefaultBounds { span }); + } + } + } + }; + search_bounds(ast_bounds); + if let Some((self_ty, where_clause)) = self_ty_where_predicates { + for clause in where_clause { + if let hir::WherePredicate::BoundPredicate(pred) = clause { + if pred.is_param_bound(self_ty.to_def_id()) { + search_bounds(pred.bounds); + } + } + } + } + + 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. + } + } + 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); + } + + /// This helper takes a *converted* parameter type (`param_ty`) + /// and an *unconverted* list of bounds: + /// + /// ```text + /// fn foo<T: Debug> + /// ^ ^^^^^ `ast_bounds` parameter, in HIR form + /// | + /// `param_ty`, in ty form + /// ``` + /// + /// It adds these `ast_bounds` into the `bounds` structure. + /// + /// **A note on binders:** there is an implied binder around + /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` + /// for more details. + #[instrument(level = "debug", skip(self, ast_bounds, bounds))] + pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>( + &self, + param_ty: Ty<'tcx>, + ast_bounds: I, + bounds: &mut Bounds<'tcx>, + bound_vars: &'tcx ty::List<ty::BoundVariableKind>, + only_self_bounds: OnlySelfBounds, + ) { + for ast_bound in ast_bounds { + match ast_bound { + hir::GenericBound::Trait(poly_trait_ref, modifier) => { + let (constness, polarity) = match modifier { + hir::TraitBoundModifier::MaybeConst => { + (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive) + } + hir::TraitBoundModifier::None => { + (ty::BoundConstness::NotConst, ty::ImplPolarity::Positive) + } + hir::TraitBoundModifier::Negative => { + (ty::BoundConstness::NotConst, ty::ImplPolarity::Negative) + } + hir::TraitBoundModifier::Maybe => continue, + }; + let _ = self.instantiate_poly_trait_ref( + &poly_trait_ref.trait_ref, + poly_trait_ref.span, + constness, + polarity, + param_ty, + bounds, + false, + only_self_bounds, + ); + } + &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { + self.instantiate_lang_item_trait_ref( + lang_item, + span, + hir_id, + args, + param_ty, + bounds, + only_self_bounds, + ); + } + hir::GenericBound::Outlives(lifetime) => { + let region = self.ast_region_to_region(lifetime, None); + bounds.push_region_bound( + self.tcx(), + ty::Binder::bind_with_vars( + ty::OutlivesPredicate(param_ty, region), + bound_vars, + ), + lifetime.ident.span, + ); + } + } + } + } + + /// Translates a list of bounds from the HIR into the `Bounds` data structure. + /// The self-type for the bounds is given by `param_ty`. + /// + /// Example: + /// + /// ```ignore (illustrative) + /// fn foo<T: Bar + Baz>() { } + /// // ^ ^^^^^^^^^ ast_bounds + /// // param_ty + /// ``` + /// + /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be + /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the + /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. + /// + /// `span` should be the declaration size of the parameter. + pub(crate) fn compute_bounds( + &self, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::GenericBound<'_>], + filter: PredicateFilter, + ) -> Bounds<'tcx> { + let mut bounds = Bounds::default(); + + let only_self_bounds = match filter { + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { + OnlySelfBounds(false) + } + PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true), + }; + + self.add_bounds( + param_ty, + ast_bounds.iter().filter(|bound| { + match filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfAndAssociatedTypeBounds => true, + PredicateFilter::SelfThatDefines(assoc_name) => { + if let Some(trait_ref) = bound.trait_ref() + && let Some(trait_did) = trait_ref.trait_def_id() + && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name) + { + true + } else { + false + } + } + } + }), + &mut bounds, + ty::List::empty(), + only_self_bounds, + ); + debug!(?bounds); + + bounds + } + + /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates + /// onto `bounds`. + /// + /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the + /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* + /// the binder (e.g., `&'a u32`) and hence may reference bound regions. + #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))] + pub(super) fn add_predicates_for_ast_type_binding( + &self, + hir_ref_id: hir::HirId, + trait_ref: ty::PolyTraitRef<'tcx>, + binding: &ConvertedBinding<'_, 'tcx>, + bounds: &mut Bounds<'tcx>, + speculative: bool, + dup_bindings: &mut FxHashMap<DefId, Span>, + path_span: Span, + constness: ty::BoundConstness, + only_self_bounds: OnlySelfBounds, + polarity: ty::ImplPolarity, + ) -> Result<(), ErrorGuaranteed> { + // Given something like `U: SomeTrait<T = X>`, we want to produce a + // predicate like `<U as SomeTrait>::T = X`. This is somewhat + // subtle in the event that `T` is defined in a supertrait of + // `SomeTrait`, because in that case we need to upcast. + // + // That is, consider this case: + // + // ``` + // trait SubTrait: SuperTrait<i32> { } + // trait SuperTrait<A> { type T; } + // + // ... B: SubTrait<T = foo> ... + // ``` + // + // We want to produce `<B as SuperTrait<i32>>::T == foo`. + + let tcx = self.tcx(); + + let return_type_notation = + binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation; + + let candidate = if return_type_notation { + if self.trait_defines_associated_item_named( + trait_ref.def_id(), + ty::AssocKind::Fn, + binding.item_name, + ) { + trait_ref + } else { + self.one_bound_for_assoc_method( + traits::supertraits(tcx, trait_ref), + trait_ref.print_only_trait_path(), + binding.item_name, + path_span, + )? + } + } else if self.trait_defines_associated_item_named( + trait_ref.def_id(), + ty::AssocKind::Type, + binding.item_name, + ) { + // Simple case: X is defined in the current trait. + trait_ref + } else { + // Otherwise, we have to walk through the supertraits to find + // those that do. + self.one_bound_for_assoc_type( + || traits::supertraits(tcx, trait_ref), + trait_ref.skip_binder().print_only_trait_name(), + binding.item_name, + path_span, + match binding.kind { + ConvertedBindingKind::Equality(term) => Some(term), + _ => None, + }, + )? + }; + + let (assoc_ident, def_scope) = + tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); + + // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead + // of calling `filter_by_name_and_kind`. + let find_item_of_kind = |kind| { + tcx.associated_items(candidate.def_id()) + .filter_by_name_unhygienic(assoc_ident.name) + .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident) + }; + let assoc_item = if return_type_notation { + find_item_of_kind(ty::AssocKind::Fn) + } else { + find_item_of_kind(ty::AssocKind::Type) + .or_else(|| find_item_of_kind(ty::AssocKind::Const)) + } + .expect("missing associated type"); + + if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) { + tcx.sess + .struct_span_err( + binding.span, + format!("{} `{}` is private", assoc_item.kind, binding.item_name), + ) + .span_label(binding.span, format!("private {}", assoc_item.kind)) + .emit(); + } + tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None); + + if !speculative { + dup_bindings + .entry(assoc_item.def_id) + .and_modify(|prev_span| { + tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified { + span: binding.span, + prev_span: *prev_span, + item_name: binding.item_name, + def_path: tcx.def_path_str(assoc_item.container_id(tcx)), + }); + }) + .or_insert(binding.span); + } + + let projection_ty = if return_type_notation { + let mut emitted_bad_param_err = false; + // If we have an method return type bound, then we need to substitute + // the method's early bound params with suitable late-bound params. + let mut num_bound_vars = candidate.bound_vars().len(); + let substs = + candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| { + let subst = match param.kind { + ty::GenericParamDefKind::Lifetime => ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(num_bound_vars), + kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), + }, + ) + .into(), + ty::GenericParamDefKind::Type { .. } => { + if !emitted_bad_param_err { + tcx.sess.emit_err( + crate::errors::ReturnTypeNotationIllegalParam::Type { + span: path_span, + param_span: tcx.def_span(param.def_id), + }, + ); + emitted_bad_param_err = true; + } + Ty::new_bound( + tcx, + ty::INNERMOST, + ty::BoundTy { + var: ty::BoundVar::from_usize(num_bound_vars), + kind: ty::BoundTyKind::Param(param.def_id, param.name), + }, + ) + .into() + } + ty::GenericParamDefKind::Const { .. } => { + if !emitted_bad_param_err { + tcx.sess.emit_err( + crate::errors::ReturnTypeNotationIllegalParam::Const { + span: path_span, + param_span: tcx.def_span(param.def_id), + }, + ); + emitted_bad_param_err = true; + } + let ty = tcx + .type_of(param.def_id) + .no_bound_vars() + .expect("ct params cannot have early bound vars"); + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(num_bound_vars), + ty, + ) + .into() + } + }; + num_bound_vars += 1; + subst + }); + + // Next, we need to check that the return-type notation is being used on + // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). + let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output(); + let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() + && tcx.is_impl_trait_in_trait(alias_ty.def_id) + { + alias_ty + } else { + return Err(self.tcx().sess.emit_err( + crate::errors::ReturnTypeNotationOnNonRpitit { + span: binding.span, + ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output), + fn_span: tcx.hir().span_if_local(assoc_item.def_id), + note: (), + }, + )); + }; + + // Finally, move the fn return type's bound vars over to account for the early bound + // params (and trait ref's late bound params). This logic is very similar to + // `Predicate::subst_supertrait`, and it's no coincidence why. + let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); + let subst_output = ty::EarlyBinder::bind(shifted_output).subst(tcx, substs); + + let bound_vars = tcx.late_bound_vars(binding.hir_id); + ty::Binder::bind_with_vars(subst_output, bound_vars) + } else { + // Include substitutions for generic parameters of associated types + candidate.map_bound(|trait_ref| { + let ident = Ident::new(assoc_item.name, binding.item_name.span); + let item_segment = hir::PathSegment { + ident, + hir_id: binding.hir_id, + res: Res::Err, + args: Some(binding.gen_args), + infer_args: false, + }; + + let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item( + path_span, + assoc_item.def_id, + &item_segment, + trait_ref.substs, + ); + + debug!(?substs_trait_ref_and_assoc_item); + + tcx.mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item) + }) + }; + + if !speculative { + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref or assoc_item. These are not well-formed. + // + // Example: + // + // for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad + // for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok + if let ConvertedBindingKind::Equality(ty) = binding.kind { + let late_bound_in_trait_ref = + tcx.collect_constrained_late_bound_regions(&projection_ty); + let late_bound_in_ty = + tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty)); + debug!(?late_bound_in_trait_ref); + debug!(?late_bound_in_ty); + + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ + self.validate_late_bound_regions( + late_bound_in_trait_ref, + late_bound_in_ty, + |br_name| { + struct_span_err!( + tcx.sess, + binding.span, + E0582, + "binding for associated type `{}` references {}, \ + which does not appear in the trait input types", + binding.item_name, + br_name + ) + }, + ); + } + } + + match binding.kind { + ConvertedBindingKind::Equality(..) if return_type_notation => { + return Err(self.tcx().sess.emit_err( + crate::errors::ReturnTypeNotationEqualityBound { span: binding.span }, + )); + } + ConvertedBindingKind::Equality(mut term) => { + // "Desugar" a constraint like `T: Iterator<Item = u32>` this to + // the "projection predicate" for: + // + // `<T as Iterator>::Item = u32` + let assoc_item_def_id = projection_ty.skip_binder().def_id; + let def_kind = tcx.def_kind(assoc_item_def_id); + match (def_kind, term.unpack()) { + (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_)) + | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (), + (_, _) => { + let got = if let Some(_) = term.ty() { "type" } else { "constant" }; + let expected = tcx.def_descr(assoc_item_def_id); + let mut err = tcx.sess.struct_span_err( + binding.span, + format!("expected {expected} bound, found {got}"), + ); + err.span_note( + tcx.def_span(assoc_item_def_id), + format!("{expected} defined here"), + ); + + if let hir::def::DefKind::AssocConst = def_kind + && 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", + format!("{} = {{ const }}", binding.item_name), + Applicability::HasPlaceholders, + ); + } + let reported = err.emit(); + term = match def_kind { + hir::def::DefKind::AssocTy => Ty::new_error(tcx, reported).into(), + hir::def::DefKind::AssocConst => ty::Const::new_error( + tcx, + reported, + tcx.type_of(assoc_item_def_id) + .subst(tcx, projection_ty.skip_binder().substs), + ) + .into(), + _ => unreachable!(), + }; + } + } + bounds.push_projection_bound( + tcx, + projection_ty + .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }), + binding.span, + ); + } + ConvertedBindingKind::Constraint(ast_bounds) => { + // "Desugar" a constraint like `T: Iterator<Item: Debug>` to + // + // `<T as Iterator>::Item: Debug` + // + // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` + // parameter to have a skipped binder. + // + // NOTE: If `only_self_bounds` is true, do NOT expand this associated + // type bound into a trait predicate, since we only want to add predicates + // for the `Self` type. + if !only_self_bounds.0 { + let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder()); + self.add_bounds( + param_ty, + ast_bounds.iter(), + bounds, + projection_ty.bound_vars(), + only_self_bounds, + ); + } + } + } + Ok(()) + } +} diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 7b922f5d5..ddf99853b 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -122,9 +122,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let all_candidate_names: Vec<_> = all_candidates() .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, - ) + .filter_map(|item| { + if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type { + Some(item.name) + } else { + None + } + }) .collect(); if let (Some(suggested_name), true) = ( @@ -159,9 +163,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .flat_map(|trait_def_id| { self.tcx().associated_items(*trait_def_id).in_definition_order() }) - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, - ) + .filter_map(|item| { + if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type { + Some(item.name) + } else { + None + } + }) .collect(); if let (Some(suggested_name), true) = ( @@ -343,13 +351,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let format_pred = |pred: ty::Predicate<'tcx>| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { let pred = bound_predicate.rebind(pred); // `<Foo as Iterator>::Item = String`. let projection_ty = pred.skip_binder().projection_ty; let substs_with_infer_self = tcx.mk_substs_from_iter( - std::iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into()) + std::iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into()) .chain(projection_ty.substs.iter().skip(1)), ); @@ -364,7 +372,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bound_span_label(projection_ty.self_ty(), &obligation, &quiet); Some((obligation, projection_ty.self_ty())) } - ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => { let p = poly_trait_ref.trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs new file mode 100644 index 000000000..05a3ab63d --- /dev/null +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -0,0 +1,124 @@ +use rustc_ast::TraitObjectSyntax; +use rustc_errors::{Diagnostic, StashKey}; +use rustc_hir as hir; +use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability}; +use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; + +use super::AstConv; + +impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { + /// Make sure that we are in the condition to suggest the blanket implementation. + pub(super) fn maybe_lint_blanket_trait_impl( + &self, + self_ty: &hir::Ty<'_>, + diag: &mut Diagnostic, + ) { + let tcx = self.tcx(); + let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; + 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, .. + }), + .. + }) = 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; }; + // check if the trait has generics, to make a correct suggestion + let param_name = generics.params.next_type_param_name(None); + + let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() { + (span, format!(", {}: {}", param_name, impl_trait_name)) + } else { + (generics.span, format!("<{}: {}>", param_name, impl_trait_name)) + }; + diag.multipart_suggestion( + 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, + ], + Applicability::MaybeIncorrect, + ); + } + } + + pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) { + let tcx = self.tcx(); + if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = + self_ty.kind + { + let needs_bracket = in_path + && !tcx + .sess + .source_map() + .span_to_prev_source(self_ty.span) + .ok() + .is_some_and(|s| s.trim_end().ends_with('<')); + + let is_global = poly_trait_ref.trait_ref.path.is_global(); + + let mut sugg = Vec::from_iter([( + self_ty.span.shrink_to_lo(), + format!( + "{}dyn {}", + if needs_bracket { "<" } else { "" }, + if is_global { "(" } else { "" }, + ), + )]); + + if is_global || needs_bracket { + sugg.push(( + self_ty.span.shrink_to_hi(), + format!( + "{}{}", + if is_global { ")" } else { "" }, + if needs_bracket { ">" } else { "" }, + ), + )); + } + + if self_ty.span.edition().rust_2021() { + let msg = "trait objects must include the `dyn` keyword"; + let label = "add `dyn` keyword before this trait"; + let mut diag = + rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg); + if self_ty.span.can_be_used_for_suggestions() { + diag.multipart_suggestion_verbose( + label, + sugg, + Applicability::MachineApplicable, + ); + } + // check if the impl trait that we are considering is a impl of a local trait + self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); + diag.stash(self_ty.span, StashKey::TraitMissingMethod); + } else { + let msg = "trait objects without an explicit `dyn` are deprecated"; + tcx.struct_span_lint_hir( + BARE_TRAIT_OBJECTS, + self_ty.hir_id, + self_ty.span, + msg, + |lint| { + lint.multipart_suggestion_verbose( + "use `dyn`", + sugg, + Applicability::MachineApplicable, + ); + self.maybe_lint_blanket_trait_impl(&self_ty, lint); + lint + }, + ); + } + } + } +} diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 2c60a0624..3d6984628 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2,53 +2,45 @@ //! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an //! instance of `AstConv`. +mod bounds; mod errors; pub mod generics; +mod lint; +mod object_safety; use crate::astconv::errors::prohibit_assoc_ty_binding; use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args}; use crate::bounds::Bounds; use crate::collect::HirPlaceholderCollector; -use crate::errors::{ - AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, - TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified, -}; +use crate::errors::{AmbiguousLifetimeBound, TypeofReservedKeywordUsed}; use crate::middle::resolve_bound_vars as rbv; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError, - MultiSpan, StashKey, + MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::middle::stability::AllowUnstable; -use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::ty::{DynKind, ToPredicate}; -use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; +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_target::spec::abi; -use rustc_trait_selection::traits::error_reporting::{ - report_object_safety_error, suggestions::NextTypeParamName, -}; use rustc_trait_selection::traits::wf::object_region_bounds; -use rustc_trait_selection::traits::{self, astconv_object_safety_violations, ObligationCtxt}; +use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCtxt}; +use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use smallvec::{smallvec, SmallVec}; -use std::collections::BTreeSet; use std::fmt::Display; use std::slice; @@ -58,6 +50,24 @@ pub struct PathSeg(pub DefId, pub usize); #[derive(Copy, Clone, Debug)] pub struct OnlySelfBounds(pub bool); +#[derive(Copy, Clone, Debug)] +pub enum PredicateFilter { + /// All predicates may be implied by the trait. + All, + + /// Only traits that reference `Self: ..` are implied by the trait. + SelfOnly, + + /// Only traits that reference `Self: ..` and define an associated type + /// with the given ident are implied by the trait. + SelfThatDefines(Ident), + + /// Only traits that reference `Self: ..` and their associated type bounds. + /// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr` + /// and `<Self as Tr>::A: B`. + SelfAndAssociatedTypeBounds, +} + pub trait AstConv<'tcx> { fn tcx(&self) -> TyCtxt<'tcx>; @@ -239,7 +249,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { var: ty::BoundVar::from_u32(index), kind: ty::BrNamed(def_id, name), }; - tcx.mk_re_late_bound(debruijn, br) + ty::Region::new_late_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { @@ -247,12 +257,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; - tcx.mk_re_early_bound(ty::EarlyBoundRegion { def_id, index, name }) + ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion { def_id, index, name }) } Some(rbv::ResolvedArg::Free(scope, id)) => { let name = lifetime_name(id.expect_local()); - tcx.mk_re_free(scope, ty::BrNamed(id, name)) + ty::Region::new_free(tcx, scope, ty::BrNamed(id, name)) // (*) -- not late-bound, won't change } @@ -269,7 +279,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // elision. `resolve_lifetime` should have // reported an error in this case -- but if // not, let's error out. - tcx.mk_re_error_with_message( + ty::Region::new_error_with_message( + tcx, lifetime.ident.span, "unelided lifetime in signature", ) @@ -432,7 +443,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) { self.inferred_params.push(ty.span); - tcx.ty_error_misc().into() + Ty::new_misc_error(tcx).into() } else { self.astconv.ast_ty_to_ty(ty).into() } @@ -463,7 +474,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv.ct_infer(ty, Some(param), inf.span).into() } else { self.inferred_params.push(inf.span); - tcx.const_error_misc(ty).into() + ty::Const::new_misc_error(tcx, ty).into() } } _ => unreachable!(), @@ -485,7 +496,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!(?param, "unelided lifetime in signature"); // This indicates an illegal lifetime in a non-assoc-trait position - tcx.mk_re_error_with_message( + ty::Region::new_error_with_message( + tcx, self.span, "unelided lifetime in signature", ) @@ -500,14 +512,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { _ => false, }) { // Avoid ICE #86756 when type error recovery goes awry. - return tcx.ty_error_misc().into(); + return Ty::new_misc_error(tcx).into(); } tcx.at(self.span).type_of(param.def_id).subst(tcx, substs).into() } else if infer_args { self.astconv.ty_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. - tcx.ty_error_misc().into() + Ty::new_misc_error(tcx).into() } } GenericParamDefKind::Const { has_default } => { @@ -517,7 +529,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .no_bound_vars() .expect("const parameter types cannot be generic"); if let Err(guar) = ty.error_reported() { - return tcx.const_error(ty, guar).into(); + return ty::Const::new_error(tcx, guar, ty).into(); } if !infer_args && has_default { tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into() @@ -526,7 +538,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv.ct_infer(ty, Some(param), self.span).into() } else { // We've already errored above about the mismatch. - tcx.const_error_misc(ty).into() + ty::Const::new_misc_error(tcx, ty).into() } } } @@ -884,551 +896,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .is_some() } - /// Sets `implicitly_sized` to true on `Bounds` if necessary - pub(crate) fn add_implicitly_sized( - &self, - bounds: &mut Bounds<'tcx>, - self_ty: Ty<'tcx>, - ast_bounds: &'tcx [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, - span: Span, - ) { - let tcx = self.tcx(); - - // Try to find an unbound in bounds. - let mut unbound = None; - 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(MultipleRelaxedDefaultBounds { span }); - } - } - } - }; - search_bounds(ast_bounds); - if let Some((self_ty, where_clause)) = self_ty_where_predicates { - for clause in where_clause { - if let hir::WherePredicate::BoundPredicate(pred) = clause { - if pred.is_param_bound(self_ty.to_def_id()) { - search_bounds(pred.bounds); - } - } - } - } - - 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. - } - } - 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); - } - - /// This helper takes a *converted* parameter type (`param_ty`) - /// and an *unconverted* list of bounds: - /// - /// ```text - /// fn foo<T: Debug> - /// ^ ^^^^^ `ast_bounds` parameter, in HIR form - /// | - /// `param_ty`, in ty form - /// ``` - /// - /// It adds these `ast_bounds` into the `bounds` structure. - /// - /// **A note on binders:** there is an implied binder around - /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` - /// for more details. - #[instrument(level = "debug", skip(self, ast_bounds, bounds))] - pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>( - &self, - param_ty: Ty<'tcx>, - ast_bounds: I, - bounds: &mut Bounds<'tcx>, - bound_vars: &'tcx ty::List<ty::BoundVariableKind>, - only_self_bounds: OnlySelfBounds, - ) { - for ast_bound in ast_bounds { - match ast_bound { - hir::GenericBound::Trait(poly_trait_ref, modifier) => { - let (constness, polarity) = match modifier { - hir::TraitBoundModifier::MaybeConst => { - (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive) - } - hir::TraitBoundModifier::None => { - (ty::BoundConstness::NotConst, ty::ImplPolarity::Positive) - } - hir::TraitBoundModifier::Negative => { - (ty::BoundConstness::NotConst, ty::ImplPolarity::Negative) - } - hir::TraitBoundModifier::Maybe => continue, - }; - let _ = self.instantiate_poly_trait_ref( - &poly_trait_ref.trait_ref, - poly_trait_ref.span, - constness, - polarity, - param_ty, - bounds, - false, - only_self_bounds, - ); - } - &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { - self.instantiate_lang_item_trait_ref( - lang_item, - span, - hir_id, - args, - param_ty, - bounds, - only_self_bounds, - ); - } - hir::GenericBound::Outlives(lifetime) => { - let region = self.ast_region_to_region(lifetime, None); - bounds.push_region_bound( - self.tcx(), - ty::Binder::bind_with_vars( - ty::OutlivesPredicate(param_ty, region), - bound_vars, - ), - lifetime.ident.span, - ); - } - } - } - } - - /// Translates a list of bounds from the HIR into the `Bounds` data structure. - /// The self-type for the bounds is given by `param_ty`. - /// - /// Example: - /// - /// ```ignore (illustrative) - /// fn foo<T: Bar + Baz>() { } - /// // ^ ^^^^^^^^^ ast_bounds - /// // param_ty - /// ``` - /// - /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be - /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the - /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. - /// - /// `span` should be the declaration size of the parameter. - pub(crate) fn compute_bounds( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], - only_self_bounds: OnlySelfBounds, - ) -> Bounds<'tcx> { - let mut bounds = Bounds::default(); - self.add_bounds( - param_ty, - ast_bounds.iter(), - &mut bounds, - ty::List::empty(), - only_self_bounds, - ); - debug!(?bounds); - - bounds - } - - /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type - /// named `assoc_name` into ty::Bounds. Ignore the rest. - pub(crate) fn compute_bounds_that_match_assoc_item( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], - assoc_name: Ident, - ) -> Bounds<'tcx> { - let mut result = Vec::new(); - - for ast_bound in ast_bounds { - if let Some(trait_ref) = ast_bound.trait_ref() - && let Some(trait_did) = trait_ref.trait_def_id() - && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name) - { - result.push(ast_bound.clone()); - } - } - - let mut bounds = Bounds::default(); - self.add_bounds( - param_ty, - result.iter(), - &mut bounds, - ty::List::empty(), - OnlySelfBounds(true), - ); - debug!(?bounds); - - bounds - } - - /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates - /// onto `bounds`. - /// - /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the - /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* - /// the binder (e.g., `&'a u32`) and hence may reference bound regions. - #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))] - fn add_predicates_for_ast_type_binding( - &self, - hir_ref_id: hir::HirId, - trait_ref: ty::PolyTraitRef<'tcx>, - binding: &ConvertedBinding<'_, 'tcx>, - bounds: &mut Bounds<'tcx>, - speculative: bool, - dup_bindings: &mut FxHashMap<DefId, Span>, - path_span: Span, - constness: ty::BoundConstness, - only_self_bounds: OnlySelfBounds, - polarity: ty::ImplPolarity, - ) -> Result<(), ErrorGuaranteed> { - // Given something like `U: SomeTrait<T = X>`, we want to produce a - // predicate like `<U as SomeTrait>::T = X`. This is somewhat - // subtle in the event that `T` is defined in a supertrait of - // `SomeTrait`, because in that case we need to upcast. - // - // That is, consider this case: - // - // ``` - // trait SubTrait: SuperTrait<i32> { } - // trait SuperTrait<A> { type T; } - // - // ... B: SubTrait<T = foo> ... - // ``` - // - // We want to produce `<B as SuperTrait<i32>>::T == foo`. - - let tcx = self.tcx(); - - let return_type_notation = - binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation; - - let candidate = if return_type_notation { - if self.trait_defines_associated_item_named( - trait_ref.def_id(), - ty::AssocKind::Fn, - binding.item_name, - ) { - trait_ref - } else { - self.one_bound_for_assoc_method( - traits::supertraits(tcx, trait_ref), - trait_ref.print_only_trait_path(), - binding.item_name, - path_span, - )? - } - } else if self.trait_defines_associated_item_named( - trait_ref.def_id(), - ty::AssocKind::Type, - binding.item_name, - ) { - // Simple case: X is defined in the current trait. - trait_ref - } else { - // Otherwise, we have to walk through the supertraits to find - // those that do. - self.one_bound_for_assoc_type( - || traits::supertraits(tcx, trait_ref), - trait_ref.skip_binder().print_only_trait_name(), - binding.item_name, - path_span, - match binding.kind { - ConvertedBindingKind::Equality(term) => Some(term), - _ => None, - }, - )? - }; - - let (assoc_ident, def_scope) = - tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); - - // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead - // of calling `filter_by_name_and_kind`. - let find_item_of_kind = |kind| { - tcx.associated_items(candidate.def_id()) - .filter_by_name_unhygienic(assoc_ident.name) - .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident) - }; - let assoc_item = if return_type_notation { - find_item_of_kind(ty::AssocKind::Fn) - } else { - find_item_of_kind(ty::AssocKind::Type) - .or_else(|| find_item_of_kind(ty::AssocKind::Const)) - } - .expect("missing associated type"); - - if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) { - tcx.sess - .struct_span_err( - binding.span, - format!("{} `{}` is private", assoc_item.kind, binding.item_name), - ) - .span_label(binding.span, format!("private {}", assoc_item.kind)) - .emit(); - } - tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None); - - if !speculative { - dup_bindings - .entry(assoc_item.def_id) - .and_modify(|prev_span| { - tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified { - span: binding.span, - prev_span: *prev_span, - item_name: binding.item_name, - def_path: tcx.def_path_str(assoc_item.container_id(tcx)), - }); - }) - .or_insert(binding.span); - } - - let projection_ty = if return_type_notation { - // If we have an method return type bound, then we need to substitute - // the method's early bound params with suitable late-bound params. - let mut num_bound_vars = candidate.bound_vars().len(); - let substs = - candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| { - let subst = match param.kind { - GenericParamDefKind::Lifetime => tcx - .mk_re_late_bound( - ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), - }, - ) - .into(), - GenericParamDefKind::Type { .. } => tcx - .mk_bound( - ty::INNERMOST, - ty::BoundTy { - var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundTyKind::Param(param.def_id, param.name), - }, - ) - .into(), - GenericParamDefKind::Const { .. } => { - let ty = tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("ct params cannot have early bound vars"); - tcx.mk_const( - ty::ConstKind::Bound( - ty::INNERMOST, - ty::BoundVar::from_usize(num_bound_vars), - ), - ty, - ) - .into() - } - }; - num_bound_vars += 1; - subst - }); - - // Next, we need to check that the return-type notation is being used on - // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). - let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output(); - let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() - && tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder - { - alias_ty - } else { - return Err(self.tcx().sess.emit_err( - crate::errors::ReturnTypeNotationOnNonRpitit { - span: binding.span, - ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output), - fn_span: tcx.hir().span_if_local(assoc_item.def_id), - note: (), - }, - )); - }; - - // Finally, move the fn return type's bound vars over to account for the early bound - // params (and trait ref's late bound params). This logic is very similar to - // `Predicate::subst_supertrait`, and it's no coincidence why. - let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); - let subst_output = ty::EarlyBinder(shifted_output).subst(tcx, substs); - - let bound_vars = tcx.late_bound_vars(binding.hir_id); - ty::Binder::bind_with_vars(subst_output, bound_vars) - } else { - // Include substitutions for generic parameters of associated types - candidate.map_bound(|trait_ref| { - let ident = Ident::new(assoc_item.name, binding.item_name.span); - let item_segment = hir::PathSegment { - ident, - hir_id: binding.hir_id, - res: Res::Err, - args: Some(binding.gen_args), - infer_args: false, - }; - - let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item( - path_span, - assoc_item.def_id, - &item_segment, - trait_ref.substs, - ); - - debug!(?substs_trait_ref_and_assoc_item); - - tcx.mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item) - }) - }; - - if !speculative { - // Find any late-bound regions declared in `ty` that are not - // declared in the trait-ref or assoc_item. These are not well-formed. - // - // Example: - // - // for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad - // for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok - if let ConvertedBindingKind::Equality(ty) = binding.kind { - let late_bound_in_trait_ref = - tcx.collect_constrained_late_bound_regions(&projection_ty); - let late_bound_in_ty = - tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty)); - debug!(?late_bound_in_trait_ref); - debug!(?late_bound_in_ty); - - // FIXME: point at the type params that don't have appropriate lifetimes: - // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F); - // ---- ---- ^^^^^^^ - self.validate_late_bound_regions( - late_bound_in_trait_ref, - late_bound_in_ty, - |br_name| { - struct_span_err!( - tcx.sess, - binding.span, - E0582, - "binding for associated type `{}` references {}, \ - which does not appear in the trait input types", - binding.item_name, - br_name - ) - }, - ); - } - } - - match binding.kind { - ConvertedBindingKind::Equality(..) if return_type_notation => { - return Err(self.tcx().sess.emit_err( - crate::errors::ReturnTypeNotationEqualityBound { span: binding.span }, - )); - } - ConvertedBindingKind::Equality(mut term) => { - // "Desugar" a constraint like `T: Iterator<Item = u32>` this to - // the "projection predicate" for: - // - // `<T as Iterator>::Item = u32` - let assoc_item_def_id = projection_ty.skip_binder().def_id; - let def_kind = tcx.def_kind(assoc_item_def_id); - match (def_kind, term.unpack()) { - (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_)) - | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (), - (_, _) => { - let got = if let Some(_) = term.ty() { "type" } else { "constant" }; - let expected = tcx.def_descr(assoc_item_def_id); - let mut err = tcx.sess.struct_span_err( - binding.span, - format!("expected {expected} bound, found {got}"), - ); - err.span_note( - tcx.def_span(assoc_item_def_id), - format!("{expected} defined here"), - ); - - if let hir::def::DefKind::AssocConst = def_kind - && 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", - format!("{} = {{ const }}", binding.item_name), - Applicability::HasPlaceholders, - ); - } - let reported = err.emit(); - term = match def_kind { - hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(), - hir::def::DefKind::AssocConst => tcx - .const_error( - tcx.type_of(assoc_item_def_id) - .subst(tcx, projection_ty.skip_binder().substs), - reported, - ) - .into(), - _ => unreachable!(), - }; - } - } - bounds.push_projection_bound( - tcx, - projection_ty - .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }), - binding.span, - ); - } - ConvertedBindingKind::Constraint(ast_bounds) => { - // "Desugar" a constraint like `T: Iterator<Item: Debug>` to - // - // `<T as Iterator>::Item: Debug` - // - // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` - // parameter to have a skipped binder. - // - // NOTE: If `only_self_bounds` is true, do NOT expand this associated - // type bound into a trait predicate, since we only want to add predicates - // for the `Self` type. - if !only_self_bounds.0 { - let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder()); - self.add_bounds( - param_ty, - ast_bounds.iter(), - bounds, - projection_ty.bound_vars(), - only_self_bounds, - ); - } - } - } - Ok(()) - } - fn ast_path_to_ty( &self, span: Span, @@ -1436,384 +903,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment: &hir::PathSegment<'_>, ) -> Ty<'tcx> { let substs = self.ast_path_substs_for_ty(span, did, item_segment); - self.tcx().at(span).type_of(did).subst(self.tcx(), substs) - } - - fn conv_object_ty_poly_trait_ref( - &self, - span: Span, - hir_trait_bounds: &[hir::PolyTraitRef<'_>], - lifetime: &hir::Lifetime, - borrowed: bool, - representation: DynKind, - ) -> Ty<'tcx> { - let tcx = self.tcx(); - - let mut bounds = Bounds::default(); - let mut potential_assoc_types = Vec::new(); - let dummy_self = self.tcx().types.trait_object_dummy_self; - for trait_bound in hir_trait_bounds.iter().rev() { - if let GenericArgCountResult { - correct: - Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), - .. - } = self.instantiate_poly_trait_ref( - &trait_bound.trait_ref, - trait_bound.span, - ty::BoundConstness::NotConst, - ty::ImplPolarity::Positive, - dummy_self, - &mut bounds, - false, - // FIXME: This should be `true`, but we don't really handle - // associated type bounds or type aliases in objects in a way - // that makes this meaningful, I think. - OnlySelfBounds(false), - ) { - potential_assoc_types.extend(cur_potential_assoc_types); - } - } - - let mut trait_bounds = vec![]; - let mut projection_bounds = vec![]; - for (pred, span) in bounds.predicates() { - let bound_pred = pred.kind(); - match bound_pred.skip_binder() { - ty::PredicateKind::Clause(clause) => match clause { - ty::Clause::Trait(trait_pred) => { - assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive); - trait_bounds.push(( - bound_pred.rebind(trait_pred.trait_ref), - span, - trait_pred.constness, - )); - } - ty::Clause::Projection(proj) => { - projection_bounds.push((bound_pred.rebind(proj), span)); - } - ty::Clause::TypeOutlives(_) => { - // Do nothing, we deal with regions separately - } - ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(), - }, - ty::PredicateKind::WellFormed(_) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(_, _, _) - | ty::PredicateKind::Subtype(_) - | ty::PredicateKind::Coerce(_) - | ty::PredicateKind::ConstEvaluatable(_) - | ty::PredicateKind::ConstEquate(_, _) - | ty::PredicateKind::TypeWellFormedFromEnv(_) - | ty::PredicateKind::Ambiguous => bug!(), - } - } - - // Expand trait aliases recursively and check that only one regular (non-auto) trait - // is used and no 'maybe' bounds are used. - let expanded_traits = - traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b))); - - let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits - .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self) - .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); - if regular_traits.len() > 1 { - let first_trait = ®ular_traits[0]; - let additional_trait = ®ular_traits[1]; - let mut err = struct_span_err!( - tcx.sess, - additional_trait.bottom().1, - E0225, - "only auto traits can be used as additional traits in a trait object" - ); - additional_trait.label_with_exp_info( - &mut err, - "additional non-auto trait", - "additional use", - ); - first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); - err.help(format!( - "consider creating a new trait with all of these as supertraits and using that \ - trait here instead: `trait NewTrait: {} {{}}`", - regular_traits - .iter() - .map(|t| t.trait_ref().print_only_trait_path().to_string()) - .collect::<Vec<_>>() - .join(" + "), - )); - err.note( - "auto-traits like `Send` and `Sync` are traits that have special properties; \ - for more information on them, visit \ - <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>", - ); - err.emit(); - } - - if regular_traits.is_empty() && auto_traits.is_empty() { - let trait_alias_span = trait_bounds - .iter() - .map(|&(trait_ref, _, _)| trait_ref.def_id()) - .find(|&trait_ref| tcx.is_trait_alias(trait_ref)) - .map(|trait_ref| tcx.def_span(trait_ref)); - let reported = - tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }); - return tcx.ty_error(reported); - } - - // Check that there are no gross object safety violations; - // most importantly, that the supertraits don't contain `Self`, - // to avoid ICEs. - for item in ®ular_traits { - let object_safety_violations = - astconv_object_safety_violations(tcx, item.trait_ref().def_id()); - if !object_safety_violations.is_empty() { - let reported = report_object_safety_error( - tcx, - span, - item.trait_ref().def_id(), - &object_safety_violations, - ) - .emit(); - return tcx.ty_error(reported); - } - } - - // Use a `BTreeSet` to keep output in a more consistent order. - let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default(); - - let regular_traits_refs_spans = trait_bounds - .into_iter() - .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); - - for (base_trait_ref, span, constness) in regular_traits_refs_spans { - assert_eq!(constness, ty::BoundConstness::NotConst); - let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx); - for pred in traits::elaborate(tcx, [base_pred]) { - debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred); - - let bound_predicate = pred.kind(); - match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { - let pred = bound_predicate.rebind(pred); - associated_types.entry(span).or_default().extend( - tcx.associated_items(pred.def_id()) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) - .filter(|item| tcx.opt_rpitit_info(item.def_id).is_none()) - .map(|item| item.def_id), - ); - } - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { - let pred = bound_predicate.rebind(pred); - // A `Self` within the original bound will be substituted with a - // `trait_object_dummy_self`, so check for that. - let references_self = match pred.skip_binder().term.unpack() { - ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - ty::TermKind::Const(c) => { - c.ty().walk().any(|arg| arg == dummy_self.into()) - } - }; - - // If the projection output contains `Self`, force the user to - // elaborate it explicitly to avoid a lot of complexity. - // - // The "classically useful" case is the following: - // ``` - // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput { - // type MyOutput; - // } - // ``` - // - // Here, the user could theoretically write `dyn MyTrait<Output = X>`, - // but actually supporting that would "expand" to an infinitely-long type - // `fix $ Ï„ → dyn MyTrait<MyOutput = X, Output = <Ï„ as MyTrait>::MyOutput`. - // - // Instead, we force the user to write - // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See - // the discussion in #56288 for alternatives. - if !references_self { - // Include projections defined on supertraits. - projection_bounds.push((pred, span)); - } - } - _ => (), - } - } - } - - for (projection_bound, _) in &projection_bounds { - for def_ids in associated_types.values_mut() { - def_ids.remove(&projection_bound.projection_def_id()); - } - } - - self.complain_about_missing_associated_types( - associated_types, - potential_assoc_types, - hir_trait_bounds, - ); - - // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as - // `dyn Trait + Send`. - // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering - // the bounds - let mut duplicates = FxHashSet::default(); - auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id())); - debug!("regular_traits: {:?}", regular_traits); - debug!("auto_traits: {:?}", auto_traits); - - // Erase the `dummy_self` (`trait_object_dummy_self`) used above. - let existential_trait_refs = regular_traits.iter().map(|i| { - i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { - assert_eq!(trait_ref.self_ty(), dummy_self); - - // Verify that `dummy_self` did not leak inside default type parameters. This - // could not be done at path creation, since we need to see through trait aliases. - let mut missing_type_params = vec![]; - let mut references_self = false; - let generics = tcx.generics_of(trait_ref.def_id); - let substs: Vec<_> = trait_ref - .substs - .iter() - .enumerate() - .skip(1) // Remove `Self` for `ExistentialPredicate`. - .map(|(index, arg)| { - if arg == dummy_self.into() { - let param = &generics.params[index]; - missing_type_params.push(param.name); - return tcx.ty_error_misc().into(); - } else if arg.walk().any(|arg| arg == dummy_self.into()) { - references_self = true; - return tcx.ty_error_misc().into(); - } - arg - }) - .collect(); - let substs = tcx.mk_substs(&substs); - - let span = i.bottom().1; - let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { - hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) - && hir_bound.span.contains(span) - }); - self.complain_about_missing_type_params( - missing_type_params, - trait_ref.def_id, - span, - empty_generic_args, - ); + let ty = self.tcx().at(span).type_of(did); - if references_self { - let def_id = i.bottom().0.def_id(); - let mut err = struct_span_err!( - tcx.sess, - i.bottom().1, - E0038, - "the {} `{}` cannot be made into an object", - tcx.def_descr(def_id), - tcx.item_name(def_id), - ); - err.note( - rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) - .error_msg(), - ); - err.emit(); - } - - ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } - }) - }); - - let existential_projections = projection_bounds - .iter() - // We filter out traits that don't have `Self` as their self type above, - // we need to do the same for projections. - .filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self) - .map(|(bound, _)| { - bound.map_bound(|mut b| { - assert_eq!(b.projection_ty.self_ty(), dummy_self); - - // Like for trait refs, verify that `dummy_self` did not leak inside default type - // parameters. - let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return true; - } - false - }); - if references_self { - let guar = tcx.sess.delay_span_bug( - span, - "trait object projection bounds reference `Self`", - ); - let substs: Vec<_> = b - .projection_ty - .substs - .iter() - .map(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return tcx.ty_error(guar).into(); - } - arg - }) - .collect(); - b.projection_ty.substs = tcx.mk_substs(&substs); - } - - ty::ExistentialProjection::erase_self_ty(tcx, b) - }) - }); - - let regular_trait_predicates = existential_trait_refs - .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)); - let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { - ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) - }); - // N.b. principal, projections, auto traits - // FIXME: This is actually wrong with multiple principals in regards to symbol mangling - let mut v = regular_trait_predicates - .chain( - existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)), - ) - .chain(auto_trait_predicates) - .collect::<SmallVec<[_; 8]>>(); - v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); - v.dedup(); - let existential_predicates = tcx.mk_poly_existential_predicates(&v); - - // Use explicitly-specified region bound. - let region_bound = if !lifetime.is_elided() { - self.ast_region_to_region(lifetime, None) + if matches!(self.tcx().def_kind(did), DefKind::TyAlias) + && (ty.skip_binder().has_opaque_types() || self.tcx().features().lazy_type_alias) + { + // Type aliases referring to types that contain opaque types (but aren't just directly + // referencing a single opaque type) get encoded as a type alias that normalization will + // then actually instantiate the where bounds of. + let alias_ty = self.tcx().mk_alias_ty(did, substs); + Ty::new_alias(self.tcx(), ty::Weak, alias_ty) } else { - self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { - if tcx.named_bound_var(lifetime.hir_id).is_some() { - self.ast_region_to_region(lifetime, None) - } else { - self.re_infer(None, span).unwrap_or_else(|| { - let mut err = struct_span_err!( - tcx.sess, - span, - E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound" - ); - let e = if borrowed { - // We will have already emitted an error E0106 complaining about a - // missing named lifetime in `&dyn Trait`, so we elide this one. - err.delay_as_bug() - } else { - err.emit() - }; - tcx.mk_re_error(e) - }) - } - }) - }; - debug!("region_bound: {:?}", region_bound); - - let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation); - debug!("trait_object_type: {:?}", ty); - ty + ty.subst(self.tcx(), substs) + } } fn report_ambiguous_associated_type( @@ -1948,9 +1050,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { || { traits::transitive_bounds_that_define_assoc_item( tcx, - predicates.iter().filter_map(|(p, _)| { - Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref)) - }), + predicates + .iter() + .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))), assoc_name, ) }, @@ -2408,6 +1510,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) -> Result<Option<(Ty<'tcx>, DefId)>, ErrorGuaranteed> { let tcx = self.tcx(); + // Don't attempt to look up inherent associated types when the feature is not enabled. + // Theoretically it'd be fine to do so since we feature-gate their definition site. + // However, due to current limitations of the implementation (caused by us performing + // selection in AstConv), IATs can lead to cycle errors (#108491, #110106) which mask the + // feature-gate error, needlessly confusing users that use IATs by accident (#113265). + if !tcx.features().inherent_associated_types { + return Ok(None); + } + let candidates: Vec<_> = tcx .inherent_impls(adt_did) .iter() @@ -2441,32 +1552,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut fulfillment_errors = Vec::new(); let mut applicable_candidates: Vec<_> = infcx.probe(|_| { - let universe = infcx.create_next_universe(); - // Regions are not considered during selection. - // FIXME(non_lifetime_binders): Here we are "truncating" or "flattening" the universes - // of type and const binders. Is that correct in the selection phase? See also #109505. - let self_ty = tcx.replace_escaping_bound_vars_uncached( - self_ty, - FnMutDelegate { - regions: &mut |_| tcx.lifetimes.re_erased, - types: &mut |bv| { - tcx.mk_placeholder(ty::PlaceholderType { universe, bound: bv }) - }, - consts: &mut |bv, ty| { - tcx.mk_const(ty::PlaceholderConst { universe, bound: bv }, ty) - }, - }, - ); + let self_ty = self_ty + .fold_with(&mut BoundVarEraser { tcx, universe: infcx.create_next_universe() }); + + struct BoundVarEraser<'tcx> { + tcx: TyCtxt<'tcx>, + universe: ty::UniverseIndex, + } + + // FIXME(non_lifetime_binders): Don't assign the same universe to each placeholder. + impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarEraser<'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + if r.is_late_bound() { self.tcx.lifetimes.re_erased } else { r } + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match *ty.kind() { + ty::Bound(_, bv) => Ty::new_placeholder( + self.tcx, + ty::PlaceholderType { universe: self.universe, bound: bv }, + ), + _ => ty.super_fold_with(self), + } + } + + fn fold_const( + &mut self, + ct: ty::Const<'tcx>, + ) -> <TyCtxt<'tcx> as rustc_type_ir::Interner>::Const { + assert!(!ct.ty().has_escaping_bound_vars()); + + match ct.kind() { + ty::ConstKind::Bound(_, bv) => ty::Const::new_placeholder( + self.tcx, + ty::PlaceholderConst { universe: self.universe, bound: bv }, + ct.ty(), + ), + _ => ct.super_fold_with(self), + } + } + } + + let InferOk { value: self_ty, obligations } = + infcx.at(&cause, param_env).normalize(self_ty); candidates .iter() .copied() .filter(|&(impl_, _)| { infcx.probe(|_| { - let ocx = ObligationCtxt::new_in_snapshot(&infcx); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligations(obligations.clone()); - let impl_substs = infcx.fresh_item_substs(impl_); + let impl_substs = infcx.fresh_substs_for_item(span, impl_); let impl_ty = tcx.type_of(impl_).subst(tcx, impl_substs); let impl_ty = ocx.normalize(&cause, param_env, impl_ty); @@ -2522,7 +1665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .chain(substs.into_iter().skip(parent_substs.len())), ); - let ty = tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(assoc_item, substs)); + let ty = Ty::new_alias(tcx, ty::Inherent, tcx.mk_alias_ty(assoc_item, substs)); return Ok(Some((ty, assoc_item))); } @@ -2707,7 +1850,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &[path_str], item_segment.ident.name, ); - return tcx.ty_error(reported) + return Ty::new_error(tcx,reported) }; debug!("qpath_to_ty: self_type={:?}", self_ty); @@ -2730,7 +1873,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("qpath_to_ty: trait_ref={:?}", trait_ref); - tcx.mk_projection(item_def_id, item_substs) + Ty::new_projection(tcx, item_def_id, item_substs) } pub fn prohibit_generics<'a>( @@ -2993,7 +2136,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.note("`impl Trait` types can't have type parameters"); }); let substs = self.ast_path_substs_for_ty(span, did, item_segment.0); - tcx.mk_opaque(did, substs) + Ty::new_opaque(tcx, did, substs) } Res::Def( DefKind::Enum @@ -3045,16 +2188,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { var: ty::BoundVar::from_u32(index), kind: ty::BoundTyKind::Param(def_id, name), }; - tcx.mk_bound(debruijn, br) + Ty::new_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(_)) => { let def_id = def_id.expect_local(); let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)) + Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)) } - Some(rbv::ResolvedArg::Error(guar)) => tcx.ty_error(guar), + Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), } } @@ -3166,7 +2309,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { { err.span_note(impl_.self_ty.span, "not a concrete type"); } - tcx.ty_error(err.emit()) + Ty::new_error(tcx, err.emit()) } else { ty } @@ -3207,9 +2350,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { match prim_ty { hir::PrimTy::Bool => tcx.types.bool, hir::PrimTy::Char => tcx.types.char, - hir::PrimTy::Int(it) => tcx.mk_mach_int(ty::int_ty(it)), - hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(ty::uint_ty(uit)), - hir::PrimTy::Float(ft) => tcx.mk_mach_float(ty::float_ty(ft)), + hir::PrimTy::Int(it) => Ty::new_int(tcx, ty::int_ty(it)), + hir::PrimTy::Uint(uit) => Ty::new_uint(tcx, ty::uint_ty(uit)), + hir::PrimTy::Float(ft) => Ty::new_float(tcx, ty::float_ty(ft)), hir::PrimTy::Str => tcx.types.str_, } } @@ -3219,7 +2362,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .sess .delay_span_bug(path.span, "path with `Res::Err` but no error emitted"); self.set_tainted_by_errors(e); - self.tcx().ty_error(e) + Ty::new_error(self.tcx(), e) } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } @@ -3244,31 +2387,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let tcx = self.tcx(); let result_ty = match &ast_ty.kind { - hir::TyKind::Slice(ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)), + hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.ast_ty_to_ty(ty)), hir::TyKind::Ptr(mt) => { - tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl }) + Ty::new_ptr(tcx, ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl }) } hir::TyKind::Ref(region, mt) => { let r = self.ast_region_to_region(region, None); debug!(?r); let t = self.ast_ty_to_ty_inner(mt.ty, true, false); - tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) + Ty::new_ref(tcx, r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) } hir::TyKind::Never => tcx.types.never, hir::TyKind::Tup(fields) => { - tcx.mk_tup_from_iter(fields.iter().map(|t| self.ast_ty_to_ty(t))) + Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t))) } hir::TyKind::BareFn(bf) => { require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span); - tcx.mk_fn_ptr(self.ty_of_fn( - ast_ty.hir_id, - bf.unsafety, - bf.abi, - bf.decl, - None, - Some(ast_ty), - )) + Ty::new_fn_ptr( + tcx, + self.ty_of_fn(ast_ty.hir_id, bf.unsafety, bf.abi, bf.decl, None, Some(ast_ty)), + ) } hir::TyKind::TraitObject(bounds, lifetime, repr) => { self.maybe_lint_bare_trait(ast_ty, in_path); @@ -3277,7 +2416,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { TraitObjectSyntax::DynStar => ty::DynStar, }; - self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr) + self.conv_object_ty_poly_trait_ref( + ast_ty.span, + ast_ty.hir_id, + bounds, + lifetime, + borrowed, + repr, + ) } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); @@ -3288,7 +2434,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let opaque_ty = tcx.hir().item(item_id); match opaque_ty.kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { + hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => { let local_def_id = item_id.owner_id.def_id; // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as @@ -3308,7 +2454,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let ty = self.ast_ty_to_ty_inner(qself, false, true); self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false) .map(|(ty, _, _)| ty) - .unwrap_or_else(|guar| tcx.ty_error(guar)) + .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => { let def_id = tcx.require_lang_item(lang_item, Some(span)); @@ -3332,7 +2478,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }; - tcx.mk_array_with_const_len(self.ast_ty_to_ty(ty), length) + Ty::new_array_with_const_len(tcx, self.ast_ty_to_ty(ty), length) } hir::TyKind::Typeof(e) => { let ty_erased = tcx.type_of(e.def_id).subst_identity(); @@ -3356,7 +2502,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // handled specially and will not descend into this routine. self.ty_infer(None, ast_ty.span) } - hir::TyKind::Err(guar) => tcx.ty_error(*guar), + hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar), }; self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); @@ -3393,7 +2539,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }); debug!("impl_trait_ty_to_ty: substs={:?}", substs); - if in_trait { tcx.mk_projection(def_id, substs) } else { tcx.mk_opaque(def_id, substs) } + if in_trait { + Ty::new_projection(tcx, def_id, substs) + } else { + Ty::new_opaque(tcx, def_id, substs) + } } pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> { @@ -3462,7 +2612,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ast_ty_to_ty(output) } } - hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(), + hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx,), }; debug!(?output_ty); @@ -3641,148 +2791,4 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } Some(r) } - - /// Make sure that we are in the condition to suggest the blanket implementation. - fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) { - let tcx = self.tcx(); - let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; - 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, .. - }), - .. - }) = 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; }; - // check if the trait has generics, to make a correct suggestion - let param_name = generics.params.next_type_param_name(None); - - let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() { - (span, format!(", {}: {}", param_name, impl_trait_name)) - } else { - (generics.span, format!("<{}: {}>", param_name, impl_trait_name)) - }; - diag.multipart_suggestion( - 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, - ], - Applicability::MaybeIncorrect, - ); - } - } - - fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) { - let tcx = self.tcx(); - if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = - self_ty.kind - { - let needs_bracket = in_path - && !tcx - .sess - .source_map() - .span_to_prev_source(self_ty.span) - .ok() - .is_some_and(|s| s.trim_end().ends_with('<')); - - let is_global = poly_trait_ref.trait_ref.path.is_global(); - - let mut sugg = Vec::from_iter([( - self_ty.span.shrink_to_lo(), - format!( - "{}dyn {}", - if needs_bracket { "<" } else { "" }, - if is_global { "(" } else { "" }, - ), - )]); - - if is_global || needs_bracket { - sugg.push(( - self_ty.span.shrink_to_hi(), - format!( - "{}{}", - if is_global { ")" } else { "" }, - if needs_bracket { ">" } else { "" }, - ), - )); - } - - if self_ty.span.edition().rust_2021() { - let msg = "trait objects must include the `dyn` keyword"; - let label = "add `dyn` keyword before this trait"; - let mut diag = - rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg); - if self_ty.span.can_be_used_for_suggestions() { - diag.multipart_suggestion_verbose( - label, - sugg, - Applicability::MachineApplicable, - ); - } - // check if the impl trait that we are considering is a impl of a local trait - self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); - diag.stash(self_ty.span, StashKey::TraitMissingMethod); - } else { - let msg = "trait objects without an explicit `dyn` are deprecated"; - tcx.struct_span_lint_hir( - BARE_TRAIT_OBJECTS, - self_ty.hir_id, - self_ty.span, - msg, - |lint| { - lint.multipart_suggestion_verbose( - "use `dyn`", - sugg, - Applicability::MachineApplicable, - ); - self.maybe_lint_blanket_trait_impl(&self_ty, lint); - lint - }, - ); - } - } - } -} - -pub trait InferCtxtExt<'tcx> { - fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx>; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { - fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> { - InternalSubsts::for_item(self.tcx, def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } => self - .next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::SubstitutionPlaceholder, - span: self.tcx.def_span(def_id), - }) - .into(), - GenericParamDefKind::Const { .. } => { - let span = self.tcx.def_span(def_id); - let origin = ConstVariableOrigin { - kind: ConstVariableOriginKind::SubstitutionPlaceholder, - span, - }; - self.next_const_var( - self.tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - origin, - ) - .into() - } - }) - } } diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs new file mode 100644 index 000000000..9227ee934 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -0,0 +1,408 @@ +use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds}; +use crate::bounds::Bounds; +use crate::errors::TraitObjectDeclaredWithNoTraits; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; +use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{DynKind, ToPredicate}; +use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::report_object_safety_error; +use rustc_trait_selection::traits::{self, astconv_object_safety_violations}; + +use smallvec::{smallvec, SmallVec}; +use std::collections::BTreeSet; + +use super::AstConv; + +impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { + pub(super) fn conv_object_ty_poly_trait_ref( + &self, + span: Span, + hir_id: hir::HirId, + hir_trait_bounds: &[hir::PolyTraitRef<'_>], + lifetime: &hir::Lifetime, + borrowed: bool, + representation: DynKind, + ) -> Ty<'tcx> { + let tcx = self.tcx(); + + let mut bounds = Bounds::default(); + let mut potential_assoc_types = Vec::new(); + let dummy_self = self.tcx().types.trait_object_dummy_self; + for trait_bound in hir_trait_bounds.iter().rev() { + if let GenericArgCountResult { + correct: + Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), + .. + } = self.instantiate_poly_trait_ref( + &trait_bound.trait_ref, + trait_bound.span, + ty::BoundConstness::NotConst, + ty::ImplPolarity::Positive, + dummy_self, + &mut bounds, + false, + // FIXME: This should be `true`, but we don't really handle + // associated type bounds or type aliases in objects in a way + // that makes this meaningful, I think. + OnlySelfBounds(false), + ) { + potential_assoc_types.extend(cur_potential_assoc_types); + } + } + + let mut trait_bounds = vec![]; + let mut projection_bounds = vec![]; + for (pred, span) in bounds.clauses() { + let bound_pred = pred.kind(); + match bound_pred.skip_binder() { + ty::ClauseKind::Trait(trait_pred) => { + assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive); + trait_bounds.push(( + bound_pred.rebind(trait_pred.trait_ref), + span, + trait_pred.constness, + )); + } + ty::ClauseKind::Projection(proj) => { + projection_bounds.push((bound_pred.rebind(proj), span)); + } + ty::ClauseKind::TypeOutlives(_) => { + // Do nothing, we deal with regions separately + } + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::ConstArgHasType(..) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => { + bug!() + } + } + } + + // Expand trait aliases recursively and check that only one regular (non-auto) trait + // is used and no 'maybe' bounds are used. + let expanded_traits = + traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b))); + + let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits + .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self) + .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); + if regular_traits.len() > 1 { + let first_trait = ®ular_traits[0]; + let additional_trait = ®ular_traits[1]; + let mut err = struct_span_err!( + tcx.sess, + additional_trait.bottom().1, + E0225, + "only auto traits can be used as additional traits in a trait object" + ); + additional_trait.label_with_exp_info( + &mut err, + "additional non-auto trait", + "additional use", + ); + first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); + err.help(format!( + "consider creating a new trait with all of these as supertraits and using that \ + trait here instead: `trait NewTrait: {} {{}}`", + regular_traits + .iter() + .map(|t| t.trait_ref().print_only_trait_path().to_string()) + .collect::<Vec<_>>() + .join(" + "), + )); + err.note( + "auto-traits like `Send` and `Sync` are traits that have special properties; \ + for more information on them, visit \ + <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>", + ); + err.emit(); + } + + if regular_traits.is_empty() && auto_traits.is_empty() { + let trait_alias_span = trait_bounds + .iter() + .map(|&(trait_ref, _, _)| trait_ref.def_id()) + .find(|&trait_ref| tcx.is_trait_alias(trait_ref)) + .map(|trait_ref| tcx.def_span(trait_ref)); + let reported = + tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }); + return Ty::new_error(tcx, reported); + } + + // Check that there are no gross object safety violations; + // most importantly, that the supertraits don't contain `Self`, + // to avoid ICEs. + for item in ®ular_traits { + let object_safety_violations = + astconv_object_safety_violations(tcx, item.trait_ref().def_id()); + if !object_safety_violations.is_empty() { + let reported = report_object_safety_error( + tcx, + span, + item.trait_ref().def_id(), + &object_safety_violations, + ) + .emit(); + return Ty::new_error(tcx, reported); + } + } + + // Use a `BTreeSet` to keep output in a more consistent order. + let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default(); + + let regular_traits_refs_spans = trait_bounds + .into_iter() + .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); + + for (base_trait_ref, span, constness) in regular_traits_refs_spans { + assert_eq!(constness, ty::BoundConstness::NotConst); + let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx); + for pred in traits::elaborate(tcx, [base_pred]) { + debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred); + + let bound_predicate = pred.kind(); + match bound_predicate.skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + let pred = bound_predicate.rebind(pred); + associated_types.entry(span).or_default().extend( + tcx.associated_items(pred.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.opt_rpitit_info.is_none()) + .map(|item| item.def_id), + ); + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { + let pred = bound_predicate.rebind(pred); + // A `Self` within the original bound will be substituted with a + // `trait_object_dummy_self`, so check for that. + let references_self = match pred.skip_binder().term.unpack() { + ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), + ty::TermKind::Const(c) => { + c.ty().walk().any(|arg| arg == dummy_self.into()) + } + }; + + // If the projection output contains `Self`, force the user to + // elaborate it explicitly to avoid a lot of complexity. + // + // The "classically useful" case is the following: + // ``` + // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput { + // type MyOutput; + // } + // ``` + // + // Here, the user could theoretically write `dyn MyTrait<Output = X>`, + // but actually supporting that would "expand" to an infinitely-long type + // `fix $ Ï„ → dyn MyTrait<MyOutput = X, Output = <Ï„ as MyTrait>::MyOutput`. + // + // Instead, we force the user to write + // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See + // the discussion in #56288 for alternatives. + if !references_self { + // Include projections defined on supertraits. + projection_bounds.push((pred, span)); + } + } + _ => (), + } + } + } + + // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`. + // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated + // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a + // corresponding `Projection` clause + for def_ids in associated_types.values_mut() { + for (projection_bound, span) in &projection_bounds { + let def_id = projection_bound.projection_def_id(); + def_ids.remove(&def_id); + if tcx.generics_require_sized_self(def_id) { + tcx.emit_spanned_lint( + UNUSED_ASSOCIATED_TYPE_BOUNDS, + hir_id, + *span, + crate::errors::UnusedAssociatedTypeBounds { span: *span }, + ); + } + } + // If the associated type has a `where Self: Sized` bound, we do not need to constrain the associated + // type in the `dyn Trait`. + def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id)); + } + + self.complain_about_missing_associated_types( + associated_types, + potential_assoc_types, + hir_trait_bounds, + ); + + // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as + // `dyn Trait + Send`. + // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering + // the bounds + let mut duplicates = FxHashSet::default(); + auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id())); + debug!("regular_traits: {:?}", regular_traits); + debug!("auto_traits: {:?}", auto_traits); + + // Erase the `dummy_self` (`trait_object_dummy_self`) used above. + let existential_trait_refs = regular_traits.iter().map(|i| { + i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { + assert_eq!(trait_ref.self_ty(), dummy_self); + + // Verify that `dummy_self` did not leak inside default type parameters. This + // could not be done at path creation, since we need to see through trait aliases. + let mut missing_type_params = vec![]; + let mut references_self = false; + let generics = tcx.generics_of(trait_ref.def_id); + let substs: Vec<_> = trait_ref + .substs + .iter() + .enumerate() + .skip(1) // Remove `Self` for `ExistentialPredicate`. + .map(|(index, arg)| { + if arg == dummy_self.into() { + let param = &generics.params[index]; + missing_type_params.push(param.name); + return Ty::new_misc_error(tcx).into(); + } else if arg.walk().any(|arg| arg == dummy_self.into()) { + references_self = true; + return Ty::new_misc_error(tcx).into(); + } + arg + }) + .collect(); + let substs = tcx.mk_substs(&substs); + + let span = i.bottom().1; + let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { + hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) + && hir_bound.span.contains(span) + }); + self.complain_about_missing_type_params( + missing_type_params, + trait_ref.def_id, + span, + empty_generic_args, + ); + + if references_self { + let def_id = i.bottom().0.def_id(); + let mut err = struct_span_err!( + tcx.sess, + i.bottom().1, + E0038, + "the {} `{}` cannot be made into an object", + tcx.def_descr(def_id), + tcx.item_name(def_id), + ); + err.note( + rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) + .error_msg(), + ); + err.emit(); + } + + ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } + }) + }); + + let existential_projections = projection_bounds + .iter() + // We filter out traits that don't have `Self` as their self type above, + // we need to do the same for projections. + .filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self) + .map(|(bound, _)| { + bound.map_bound(|mut b| { + assert_eq!(b.projection_ty.self_ty(), dummy_self); + + // Like for trait refs, verify that `dummy_self` did not leak inside default type + // parameters. + let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return true; + } + false + }); + if references_self { + let guar = tcx.sess.delay_span_bug( + span, + "trait object projection bounds reference `Self`", + ); + let substs: Vec<_> = b + .projection_ty + .substs + .iter() + .map(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return Ty::new_error(tcx, guar).into(); + } + arg + }) + .collect(); + b.projection_ty.substs = tcx.mk_substs(&substs); + } + + ty::ExistentialProjection::erase_self_ty(tcx, b) + }) + }); + + let regular_trait_predicates = existential_trait_refs + .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)); + let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { + ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) + }); + // N.b. principal, projections, auto traits + // FIXME: This is actually wrong with multiple principals in regards to symbol mangling + let mut v = regular_trait_predicates + .chain( + existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)), + ) + .chain(auto_trait_predicates) + .collect::<SmallVec<[_; 8]>>(); + v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); + v.dedup(); + let existential_predicates = tcx.mk_poly_existential_predicates(&v); + + // Use explicitly-specified region bound. + let region_bound = if !lifetime.is_elided() { + self.ast_region_to_region(lifetime, None) + } else { + self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { + if tcx.named_bound_var(lifetime.hir_id).is_some() { + self.ast_region_to_region(lifetime, None) + } else { + self.re_infer(None, span).unwrap_or_else(|| { + let mut err = struct_span_err!( + tcx.sess, + span, + E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound" + ); + let e = if borrowed { + // We will have already emitted an error E0106 complaining about a + // missing named lifetime in `&dyn Trait`, so we elide this one. + err.delay_as_bug() + } else { + err.emit() + }; + ty::Region::new_error(tcx, e) + }) + } + }) + }; + debug!("region_bound: {:?}", region_bound); + + let ty = Ty::new_dynamic(tcx, existential_predicates, region_bound, representation); + debug!("trait_object_type: {:?}", ty); + ty + } +} diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index d6d1498d7..c07ac35cb 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // NOTE: we may still need to normalize the built-in deref in case // we have some type like `&<Ty as Trait>::Assoc`, since users of // autoderef expect this type to have been structurally normalized. - if self.infcx.tcx.trait_solver_next() + if self.infcx.next_trait_solver() && let ty::Alias(ty::Projection, _) = ty.kind() { let (normalized_ty, obligations) = self.structurally_normalize(ty)?; @@ -148,8 +148,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { return None; } - let (normalized_ty, obligations) = - self.structurally_normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, [ty]))?; + let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection( + tcx, + tcx.lang_items().deref_target()?, + [ty], + ))?; debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); @@ -161,8 +164,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { &self, ty: Ty<'tcx>, ) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> { - let tcx = self.infcx.tcx; - let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx); + let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.infcx); let cause = traits::ObligationCause::misc(self.span, self.body_id); let normalized_ty = match self diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 686066abb..531100e1f 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -23,7 +23,7 @@ use rustc_span::Span; /// include the self type (e.g., `trait_bounds`) but in others we do not #[derive(Default, PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { - pub predicates: Vec<(ty::Predicate<'tcx>, Span)>, + pub clauses: Vec<(ty::Clause<'tcx>, Span)>, } impl<'tcx> Bounds<'tcx> { @@ -33,7 +33,8 @@ impl<'tcx> Bounds<'tcx> { region: ty::PolyTypeOutlivesPredicate<'tcx>, span: Span, ) { - self.predicates.push((region.to_predicate(tcx), span)); + self.clauses + .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).to_predicate(tcx), span)); } pub fn push_trait_bound( @@ -44,9 +45,11 @@ impl<'tcx> Bounds<'tcx> { constness: ty::BoundConstness, polarity: ty::ImplPolarity, ) { - self.predicates.push(( + self.clauses.push(( trait_ref - .map_bound(|trait_ref| ty::TraitPredicate { trait_ref, constness, polarity }) + .map_bound(|trait_ref| { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness, polarity }) + }) .to_predicate(tcx), span, )); @@ -58,17 +61,20 @@ impl<'tcx> Bounds<'tcx> { projection: ty::PolyProjectionPredicate<'tcx>, span: Span, ) { - self.predicates.push((projection.to_predicate(tcx), span)); + self.clauses.push(( + projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).to_predicate(tcx), + span, + )); } pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) { let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span)); let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]); // Preferable to put this obligation first, since we report better errors for sized ambiguity. - self.predicates.insert(0, (trait_ref.without_const().to_predicate(tcx), span)); + self.clauses.insert(0, (trait_ref.to_predicate(tcx), span)); } - pub fn predicates(&self) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + '_ { - self.predicates.iter().cloned() + pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { + self.clauses.iter().cloned() } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 3b2c052e8..120545c8e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -177,7 +177,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { } // Generic statics are rejected, but we still reach this case. Err(e) => { - tcx.sess.delay_span_bug(span, e.to_string()); + tcx.sess.delay_span_bug(span, format!("{e:?}")); return; } }; @@ -224,7 +224,8 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() { return; } - check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin); + + let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin); } /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result @@ -299,7 +300,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( } } - if let ItemKind::OpaqueTy(hir::OpaqueTy { + if let ItemKind::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..), in_trait, .. @@ -307,9 +308,9 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( { let substs = InternalSubsts::identity_for_item(tcx, def_id); let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { - tcx.mk_projection(def_id.to_def_id(), substs) + Ty::new_projection(tcx, def_id.to_def_id(), substs) } else { - tcx.mk_opaque(def_id.to_def_id(), substs) + Ty::new_opaque(tcx, def_id.to_def_id(), substs) }; let mut visitor = ProhibitOpaqueVisitor { opaque_identity_ty, @@ -395,7 +396,7 @@ fn check_opaque_meets_bounds<'tcx>( def_id: LocalDefId, span: Span, origin: &hir::OpaqueTyOrigin, -) { +) -> Result<(), ErrorGuaranteed> { let defining_use_anchor = match *origin { hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id), @@ -409,7 +410,7 @@ fn check_opaque_meets_bounds<'tcx>( let ocx = ObligationCtxt::new(&infcx); let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); + let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), substs); // `ReErased` regions appear in the "parent_substs" of closures/generators. // We're ignoring them here and replacing them with fresh region variables. @@ -429,24 +430,26 @@ fn check_opaque_meets_bounds<'tcx>( Ok(()) => {} Err(ty_err) => { let ty_err = ty_err.to_string(tcx); - tcx.sess.delay_span_bug( + return Err(tcx.sess.delay_span_bug( span, format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"), - ); + )); } } // Additionally require the hidden type to be well-formed with only the generics of the opaque type. // Defining use functions may have more bounds than the opaque type, which is ok, as long as the // hidden type is well formed even without those bounds. - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into())); + let predicate = + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into()))); ocx.register_obligation(Obligation::new(tcx, misc_cause, param_env, predicate)); // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + let guar = infcx.err_ctxt().report_fulfillment_errors(&errors); + return Err(guar); } match origin { // Checked when type checking the function containing them. @@ -460,14 +463,15 @@ fn check_opaque_meets_bounds<'tcx>( if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {} // Can have different predicates to their defining use hir::OpaqueTyOrigin::TyAlias { .. } => { - let wf_tys = ocx.assumed_wf_types(param_env, span, def_id); + let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?; let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env); + ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?; } } // Clean up after ourselves let _ = infcx.take_opaque_types(); + Ok(()) } fn is_enum_of_nonnullable_ptr<'tcx>( @@ -562,8 +566,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_union(tcx, id.owner_id.def_id); } DefKind::OpaqueTy => { - let opaque = tcx.hir().expect_item(id.owner_id.def_id).expect_opaque_ty(); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + 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 && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { @@ -704,7 +708,7 @@ pub(super) fn check_specialization_validity<'tcx>( // grandparent. In that case, if parent is a `default impl`, inherited items use the // "defaultness" from the grandparent, else they are final. None => { - if tcx.impl_defaultness(parent_impl.def_id()).is_default() { + if tcx.defaultness(parent_impl.def_id()).is_default() { None } else { Some(Err(parent_impl.def_id())) @@ -718,7 +722,14 @@ pub(super) fn check_specialization_validity<'tcx>( let result = opt_result.unwrap_or(Ok(())); if let Err(parent_impl) = result { - report_forbidden_specialization(tcx, impl_item, parent_impl); + if !tcx.is_impl_trait_in_trait(impl_item) { + report_forbidden_specialization(tcx, impl_item, parent_impl); + } else { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("parent item: {:?} not marked as default", parent_impl), + ); + } } } @@ -803,7 +814,7 @@ fn check_impl_items_against_trait<'tcx>( .as_ref() .is_some_and(|node_item| node_item.item.defaultness(tcx).has_value()); - if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { + if !is_implemented && tcx.defaultness(impl_id).is_final() { missing_items.push(tcx.associated_item(trait_item_id)); } @@ -1481,7 +1492,9 @@ fn opaque_type_cycle_error( } for closure_def_id in visitor.closures { - let Some(closure_local_did) = closure_def_id.as_local() else { continue; }; + let Some(closure_local_did) = closure_def_id.as_local() else { + continue; + }; let typeck_results = tcx.typeck(closure_local_did); let mut label_match = |ty: Ty<'_>, span| { @@ -1549,7 +1562,7 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { .with_opaque_type_inference(DefiningAnchor::Bind(def_id)) .build(); - let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); + let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx); for (predicate, cause) in generator_interior_predicates { let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); fulfillment_cx.register_predicate_obligation(&infcx, obligation); 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 8bf1e0e84..22e576e34 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -19,12 +19,13 @@ use rustc_middle::ty::{ self, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, }; +use std::borrow::Cow; use std::iter; /// Checks that a method from an impl conforms to the signature of @@ -44,12 +45,7 @@ pub(super) fn compare_impl_method<'tcx>( debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); let _: Result<_, ErrorGuaranteed> = try { - compare_self_type(tcx, impl_m, trait_m, impl_trait_ref)?; - compare_number_of_generics(tcx, impl_m, trait_m, false)?; - compare_generic_param_kinds(tcx, impl_m, trait_m, false)?; - compare_number_of_method_arguments(tcx, impl_m, trait_m)?; - compare_synthetic_generics(tcx, impl_m, trait_m)?; - compare_asyncness(tcx, impl_m, trait_m)?; + check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?; compare_method_predicate_entailment( tcx, impl_m, @@ -60,6 +56,26 @@ pub(super) fn compare_impl_method<'tcx>( }; } +/// Checks a bunch of different properties of the impl/trait methods for +/// compatibility, such as asyncness, number of argument, self receiver kind, +/// and number of early- and late-bound generics. +fn check_method_is_structurally_compatible<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: ty::AssocItem, + trait_m: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, + delay: bool, +) -> Result<(), ErrorGuaranteed> { + compare_self_type(tcx, impl_m, trait_m, impl_trait_ref, delay)?; + compare_number_of_generics(tcx, impl_m, trait_m, delay)?; + compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?; + compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?; + compare_synthetic_generics(tcx, impl_m, trait_m, delay)?; + compare_asyncness(tcx, impl_m, trait_m, delay)?; + check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?; + Ok(()) +} + /// This function is best explained by example. Consider a trait with it's implementation: /// /// ```rust @@ -176,9 +192,6 @@ fn compare_method_predicate_entailment<'tcx>( let impl_m_predicates = tcx.predicates_of(impl_m.def_id); let trait_m_predicates = tcx.predicates_of(trait_m.def_id); - // Check region bounds. - check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?; - // Create obligations for each predicate declared by the impl // definition in the context of the trait's parameter // environment. We can't just use `impl_env.caller_bounds`, @@ -207,7 +220,7 @@ fn compare_method_predicate_entailment<'tcx>( // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); let param_env = ty::ParamEnv::new( - tcx.mk_predicates(&hybrid_preds.predicates), + tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing, hir::Constness::NotConst, ); @@ -258,7 +271,7 @@ fn compare_method_predicate_entailment<'tcx>( infer::HigherRankedType, tcx.fn_sig(impl_m.def_id).subst_identity(), ); - let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig)); + let unnormalized_impl_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig)); let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id); let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig); @@ -275,7 +288,7 @@ fn compare_method_predicate_entailment<'tcx>( // We also have to add the normalized trait signature // as we don't normalize during implied bounds computation. wf_tys.extend(trait_sig.inputs_and_output.iter()); - let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); + let trait_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -301,14 +314,16 @@ fn compare_method_predicate_entailment<'tcx>( return Err(emitted); } - if check_implied_wf == CheckImpliedWfMode::Check { + if check_implied_wf == CheckImpliedWfMode::Check && !(impl_sig, trait_sig).references_error() { // We need to check that the impl's args are well-formed given // the hybrid param-env (impl + trait method where-clauses). ocx.register_obligation(traits::Obligation::new( infcx.tcx, ObligationCause::dummy(), param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + unnormalized_impl_fty.into(), + ))), )); } @@ -471,7 +486,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { if let ty::ReFree(fr) = *r { - self.tcx.mk_re_free( + ty::Region::new_free( + self.tcx, fr.scope, self.mapping.get(&fr.bound_region).copied().unwrap_or(fr.bound_region), ) @@ -532,6 +548,7 @@ fn compare_asyncness<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, trait_m: ty::AssocItem, + delay: bool, ) -> Result<(), ErrorGuaranteed> { if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async { match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() { @@ -542,11 +559,14 @@ fn compare_asyncness<'tcx>( // We don't know if it's ok, but at least it's already an error. } _ => { - return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync { - span: tcx.def_span(impl_m.def_id), - method_name: trait_m.name, - trait_item_span: tcx.hir().span_if_local(trait_m.def_id), - })); + return Err(tcx + .sess + .create_err(crate::errors::AsyncTraitImplShouldBeAsync { + span: tcx.def_span(impl_m.def_id), + method_name: trait_m.name, + trait_item_span: tcx.hir().span_if_local(trait_m.def_id), + }) + .emit_unless(delay)); } }; } @@ -600,9 +620,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // First, check a few of the same things as `compare_impl_method`, // just so we don't ICE during substitution later. - compare_number_of_generics(tcx, impl_m, trait_m, true)?; - compare_generic_param_kinds(tcx, impl_m, trait_m, true)?; - check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?; + check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?; let trait_to_impl_substs = impl_trait_ref.substs; @@ -633,11 +651,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let impl_sig = ocx.normalize( &norm_cause, param_env, - infcx.instantiate_binder_with_fresh_vars( - return_span, - infer::HigherRankedType, - tcx.fn_sig(impl_m.def_id).subst_identity(), - ), + tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(impl_m.def_id).subst_identity()), ); impl_sig.error_reported()?; let impl_return_ty = impl_sig.output(); @@ -647,18 +661,21 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // them with inference variables. // We will use these inference variables to collect the hidden types of RPITITs. let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_def_id); - let unnormalized_trait_sig = tcx - .liberate_late_bound_regions( - impl_m.def_id, + let unnormalized_trait_sig = infcx + .instantiate_binder_with_fresh_vars( + return_span, + infer::HigherRankedType, tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs), ) .fold_with(&mut collector); - debug_assert_ne!( - collector.types.len(), - 0, - "expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`" - ); + if !unnormalized_trait_sig.output().references_error() { + debug_assert_ne!( + collector.types.len(), + 0, + "expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`" + ); + } let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig); trait_sig.error_reported()?; @@ -684,7 +701,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( &cause, hir.get_if_local(impl_m.def_id) .and_then(|node| node.fn_decl()) - .map(|decl| (decl.output.span(), "return type in trait".to_owned())), + .map(|decl| (decl.output.span(), Cow::from("return type in trait"))), Some(infer::ValuePairs::Terms(ExpectedFound { expected: trait_return_ty.into(), found: impl_return_ty.into(), @@ -742,15 +759,17 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let mut collected_tys = FxHashMap::default(); for (def_id, (ty, substs)) in collected_types { - match infcx.fully_resolve(ty) { - Ok(ty) => { + match infcx.fully_resolve((ty, substs)) { + Ok((ty, substs)) => { // `ty` contains free regions that we created earlier while liberating the // trait fn signature. However, projection normalization expects `ty` to // contains `def_id`'s early-bound regions. let id_substs = InternalSubsts::identity_for_item(tcx, def_id); debug!(?id_substs, ?substs); - let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> = - std::iter::zip(substs, id_substs).collect(); + let map: FxHashMap<_, _> = std::iter::zip(substs, id_substs) + .skip(tcx.generics_of(trait_m.def_id).count()) + .filter_map(|(a, b)| Some((a.as_region()?, b.as_region()?))) + .collect(); debug!(?map); // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound @@ -775,33 +794,27 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // same generics. let num_trait_substs = trait_to_impl_substs.len(); let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len(); - let ty = tcx.fold_regions(ty, |region, _| { - match region.kind() { - // Remap all free regions, which correspond to late-bound regions in the function. - ty::ReFree(_) => {} - // Remap early-bound regions as long as they don't come from the `impl` itself. - ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {} - _ => return region, - } - let Some(ty::ReEarlyBound(e)) = map.get(®ion.into()).map(|r| r.expect_region().kind()) - else { - return tcx.mk_re_error_with_message(return_span, "expected ReFree to map to ReEarlyBound") - }; - tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: e.def_id, - name: e.name, - index: (e.index as usize - num_trait_substs + num_impl_substs) as u32, - }) - }); - debug!(%ty); - collected_tys.insert(def_id, ty::EarlyBinder(ty)); + let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions { + tcx, + map, + num_trait_substs, + num_impl_substs, + def_id, + impl_def_id: impl_m.container_id(tcx), + ty, + return_span, + }) { + Ok(ty) => ty, + Err(guar) => Ty::new_error(tcx, guar), + }; + collected_tys.insert(def_id, ty::EarlyBinder::bind(ty)); } Err(err) => { let reported = tcx.sess.delay_span_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported))); + collected_tys.insert(def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, reported))); } } } @@ -877,6 +890,97 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { } } +struct RemapHiddenTyRegions<'tcx> { + tcx: TyCtxt<'tcx>, + map: FxHashMap<ty::Region<'tcx>, ty::Region<'tcx>>, + num_trait_substs: usize, + num_impl_substs: usize, + def_id: DefId, + impl_def_id: DefId, + ty: Ty<'tcx>, + return_span: Span, +} + +impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { + type Error = ErrorGuaranteed; + + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { + if let ty::Alias(ty::Opaque, ty::AliasTy { substs, def_id, .. }) = *t.kind() { + let mut mapped_substs = Vec::with_capacity(substs.len()); + for (arg, v) in std::iter::zip(substs, self.tcx.variances_of(def_id)) { + mapped_substs.push(match (arg.unpack(), v) { + // Skip uncaptured opaque substs + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, + _ => arg.try_fold_with(self)?, + }); + } + Ok(Ty::new_opaque(self.tcx, def_id, self.tcx.mk_substs(&mapped_substs))) + } else { + t.try_super_fold_with(self) + } + } + + fn try_fold_region( + &mut self, + region: ty::Region<'tcx>, + ) -> Result<ty::Region<'tcx>, Self::Error> { + match region.kind() { + // Remap all free regions, which correspond to late-bound regions in the function. + ty::ReFree(_) => {} + // Remap early-bound regions as long as they don't come from the `impl` itself, + // in which case we don't really need to renumber them. + ty::ReEarlyBound(ebr) if self.tcx.parent(ebr.def_id) != self.impl_def_id => {} + _ => return Ok(region), + } + + let e = if let Some(region) = self.map.get(®ion) { + if let ty::ReEarlyBound(e) = region.kind() { e } else { bug!() } + } else { + let guar = match region.kind() { + ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) + | ty::ReFree(ty::FreeRegion { + bound_region: ty::BoundRegionKind::BrNamed(def_id, _), + .. + }) => { + let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() { + self.tcx.def_span(opaque_ty.def_id) + } else { + self.return_span + }; + self.tcx + .sess + .struct_span_err( + return_span, + "return type captures more lifetimes than trait definition", + ) + .span_label(self.tcx.def_span(def_id), "this lifetime was captured") + .span_note( + self.tcx.def_span(self.def_id), + "hidden type must only reference lifetimes captured by this impl trait", + ) + .note(format!("hidden type inferred to be `{}`", self.ty)) + .emit() + } + _ => self.tcx.sess.delay_span_bug(DUMMY_SP, "should've been able to remap region"), + }; + return Err(guar); + }; + + Ok(ty::Region::new_early_bound( + self.tcx, + ty::EarlyBoundRegion { + def_id: e.def_id, + name: e.name, + index: (e.index as usize - self.num_trait_substs + self.num_impl_substs) as u32, + }, + )) + } +} + fn report_trait_method_mismatch<'tcx>( infcx: &InferCtxt<'tcx>, mut cause: ObligationCause<'tcx>, @@ -901,7 +1005,7 @@ fn report_trait_method_mismatch<'tcx>( if trait_m.fn_has_self_parameter => { let ty = trait_sig.inputs()[0]; - let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) { + let sugg = match ExplicitSelf::determine(ty, |ty| ty == impl_trait_ref.self_ty()) { ExplicitSelf::ByValue => "self".to_owned(), ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(), ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(), @@ -963,7 +1067,7 @@ fn report_trait_method_mismatch<'tcx>( infcx.err_ctxt().note_type_err( &mut diag, &cause, - trait_err_span.map(|sp| (sp, "type in trait".to_owned())), + trait_err_span.map(|sp| (sp, Cow::from("type in trait"))), Some(infer::ValuePairs::Sigs(ExpectedFound { expected: trait_sig, found: impl_sig })), terr, false, @@ -1095,6 +1199,7 @@ fn compare_self_type<'tcx>( impl_m: ty::AssocItem, trait_m: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, + delay: bool, ) -> Result<(), ErrorGuaranteed> { // Try to give more informative error messages about self typing // mismatches. Note that any mismatch will also be detected @@ -1143,7 +1248,7 @@ fn compare_self_type<'tcx>( } else { err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } - return Err(err.emit()); + return Err(err.emit_unless(delay)); } (true, false) => { @@ -1164,7 +1269,7 @@ fn compare_self_type<'tcx>( err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } - return Err(err.emit()); + return Err(err.emit_unless(delay)); } } @@ -1214,7 +1319,7 @@ fn compare_number_of_generics<'tcx>( // has mismatched type or const generic arguments, then the method that it's // inheriting the generics from will also have mismatched arguments, and // we'll report an error for that instead. Delay a bug for safety, though. - if tcx.opt_rpitit_info(trait_.def_id).is_some() { + if trait_.opt_rpitit_info.is_some() { return Err(tcx.sess.delay_span_bug( rustc_span::DUMMY_SP, "errors comparing numbers of generics of trait/impl functions were not emitted", @@ -1350,6 +1455,7 @@ fn compare_number_of_method_arguments<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, trait_m: ty::AssocItem, + delay: bool, ) -> Result<(), ErrorGuaranteed> { let impl_m_fty = tcx.fn_sig(impl_m.def_id); let trait_m_fty = tcx.fn_sig(trait_m.def_id); @@ -1420,7 +1526,7 @@ fn compare_number_of_method_arguments<'tcx>( ), ); - return Err(err.emit()); + return Err(err.emit_unless(delay)); } Ok(()) @@ -1430,6 +1536,7 @@ fn compare_synthetic_generics<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, trait_m: ty::AssocItem, + delay: bool, ) -> Result<(), ErrorGuaranteed> { // FIXME(chrisvittal) Clean up this function, list of FIXME items: // 1. Better messages for the span labels @@ -1549,7 +1656,7 @@ fn compare_synthetic_generics<'tcx>( } _ => unreachable!(), } - error_found = Some(err.emit()); + error_found = Some(err.emit_unless(delay)); } } if let Some(reported) = error_found { Err(reported) } else { Ok(()) } @@ -1731,7 +1838,7 @@ pub(super) fn compare_impl_const_raw( infcx.err_ctxt().note_type_err( &mut diag, &cause, - trait_c_span.map(|span| (span, "type in trait".to_owned())), + trait_c_span.map(|span| (span, Cow::from("type in trait"))), Some(infer::ValuePairs::Terms(ExpectedFound { expected: trait_ty.into(), found: impl_ty.into(), @@ -1814,7 +1921,7 @@ fn compare_type_predicate_entailment<'tcx>( let impl_ty_span = tcx.def_span(impl_ty_def_id); let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id); let param_env = ty::ParamEnv::new( - tcx.mk_predicates(&hybrid_preds.predicates), + tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing, hir::Constness::NotConst, ); @@ -1922,7 +2029,8 @@ pub(super) fn check_type_bounds<'tcx>( let kind = ty::BoundTyKind::Param(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Ty(kind); bound_vars.push(bound_var); - tcx.mk_bound( + Ty::new_bound( + tcx, ty::INNERMOST, ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, ) @@ -1932,7 +2040,8 @@ pub(super) fn check_type_bounds<'tcx>( let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); - tcx.mk_re_late_bound( + ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, ) @@ -1941,11 +2050,10 @@ pub(super) fn check_type_bounds<'tcx>( GenericParamDefKind::Const { .. } => { let bound_var = ty::BoundVariableKind::Const; bound_vars.push(bound_var); - tcx.mk_const( - ty::ConstKind::Bound( - ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), - ), + 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"), @@ -1989,7 +2097,7 @@ pub(super) fn check_type_bounds<'tcx>( .to_predicate(tcx), ), }; - ty::ParamEnv::new(tcx.mk_predicates(&predicates), Reveal::UserFacing, param_env.constness()) + ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing, param_env.constness()) }; debug!(?normalize_param_env); @@ -2003,7 +2111,7 @@ pub(super) fn check_type_bounds<'tcx>( // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the // span for an impl's associated type. Instead, for these, use the def_span for the synthesized // associated type. - let impl_ty_span = if tcx.opt_rpitit_info(impl_ty.def_id).is_some() { + let impl_ty_span = if impl_ty.opt_rpitit_info.is_some() { tcx.def_span(impl_ty_def_id) } else { match tcx.hir().get_by_def_id(impl_ty_def_id) { @@ -2015,7 +2123,7 @@ pub(super) fn check_type_bounds<'tcx>( _ => bug!(), } }; - let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id); + let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl_ty_def_id)?; let normalize_cause = ObligationCause::new( impl_ty_span, diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index e0ba255cc..13d1abe2a 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -128,7 +128,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // We don't need to normalize this param-env or anything, since we're only // substituting it with free params, so no additional param-env normalization // can occur on top of what has been done in the param_env query itself. - let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id)) + let param_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)) .subst(tcx, adt_to_impl_substs) .with_constness(tcx.constness(drop_impl_def_id)); @@ -183,7 +183,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( } RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"), RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => { - format!("{b}: {a}", a = tcx.mk_re_var(a)) + format!("{b}: {a}", a = ty::Region::new_var(tcx, a)) } }; guar = Some( diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index e8785235c..1248f991c 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use rustc_errors::{struct_span_err, DiagnosticMessage}; use rustc_hir as hir; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::spec::abi::Abi; @@ -53,14 +53,14 @@ fn equate_intrinsic_type<'tcx>( && gen_count_ok(own_counts.types, n_tps, "type") && gen_count_ok(own_counts.consts, 0, "const") { - let fty = tcx.mk_fn_ptr(sig); + let fty = Ty::new_fn_ptr(tcx, sig); let it_def_id = it.owner_id.def_id; let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType); require_same_types( tcx, &cause, ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env? - tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()), + Ty::new_fn_ptr(tcx, tcx.fn_sig(it.owner_id).subst_identity()), fty, ); } @@ -121,10 +121,11 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir if has_safe_attr != is_in_list { tcx.sess.struct_span_err( tcx.def_span(intrinsic_id), - DiagnosticMessage::Str(format!( - "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`", - tcx.item_name(intrinsic_id) - ))).emit(); + DiagnosticMessage::from(format!( + "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`", + tcx.item_name(intrinsic_id) + ) + )).emit(); } is_in_list @@ -133,7 +134,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`, /// and in `library/core/src/intrinsics.rs`. pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { - let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n))); + let param = |n| Ty::new_param(tcx, n, Symbol::intern(&format!("P{}", n))); let intrinsic_id = it.owner_id.to_def_id(); let intrinsic_name = tcx.item_name(intrinsic_id); let name_str = intrinsic_name.as_str(); @@ -144,16 +145,18 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ]); let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { - let region = tcx.mk_re_late_bound( + let region = ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }, ); - let env_region = tcx.mk_re_late_bound( + let env_region = ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv }, ); let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); - (tcx.mk_ref(env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) + (Ty::new_ref(tcx, env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) }) }; @@ -165,15 +168,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let (n_tps, inputs, output) = match split[1] { "cxchg" | "cxchgweak" => ( 1, - vec![tcx.mk_mut_ptr(param(0)), param(0), param(0)], - tcx.mk_tup(&[param(0), tcx.types.bool]), + vec![Ty::new_mut_ptr(tcx, param(0)), param(0), param(0)], + Ty::new_tup(tcx, &[param(0), tcx.types.bool]), ), - "load" => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)), - "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), + "load" => (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), + "store" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)), "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" - | "umin" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], param(0)), - "fence" | "singlethreadfence" => (0, Vec::new(), tcx.mk_unit()), + | "umin" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), + "fence" | "singlethreadfence" => (0, Vec::new(), Ty::new_unit(tcx)), op => { tcx.sess.emit_err(UnrecognizedAtomicOperation { span: it.span, op }); return; @@ -185,19 +188,19 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let (n_tps, inputs, output) = match intrinsic_name { sym::abort => (0, Vec::new(), tcx.types.never), sym::unreachable => (0, Vec::new(), tcx.types.never), - sym::breakpoint => (0, Vec::new(), tcx.mk_unit()), + sym::breakpoint => (0, Vec::new(), Ty::new_unit(tcx)), sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => { (1, Vec::new(), tcx.types.usize) } sym::size_of_val | sym::min_align_of_val => { - (1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize) + (1, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } sym::rustc_peek => (1, vec![param(0)], param(0)), sym::caller_location => (0, vec![], tcx.caller_location_ty()), sym::assert_inhabited | sym::assert_zero_valid - | sym::assert_mem_uninitialized_valid => (1, Vec::new(), tcx.mk_unit()), - sym::forget => (1, vec![param(0)], tcx.mk_unit()), + | sym::assert_mem_uninitialized_valid => (1, Vec::new(), Ty::new_unit(tcx)), + sym::forget => (1, vec![param(0)], Ty::new_unit(tcx)), sym::transmute | sym::transmute_unchecked => (2, vec![param(0)], param(1)), sym::prefetch_read_data | sym::prefetch_write_data @@ -205,75 +208,79 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { | sym::prefetch_write_instruction => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), tcx.types.i32, ], - tcx.mk_unit(), + Ty::new_unit(tcx), ), - sym::drop_in_place => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()), + sym::drop_in_place => (1, vec![Ty::new_mut_ptr(tcx, param(0))], Ty::new_unit(tcx)), sym::needs_drop => (1, Vec::new(), tcx.types.bool), - sym::type_name => (1, Vec::new(), tcx.mk_static_str()), - sym::type_id => (1, Vec::new(), tcx.types.u64), + sym::type_name => (1, Vec::new(), Ty::new_static_str(tcx)), + sym::type_id => (1, Vec::new(), tcx.types.u128), sym::offset => (2, vec![param(0), param(1)], param(0)), sym::arith_offset => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), tcx.types.isize, ], - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), sym::option_payload_ptr => { let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None); let p0 = param(0); ( 1, - vec![tcx.mk_ptr(ty::TypeAndMut { - ty: tcx.mk_adt( - tcx.adt_def(option_def_id), - tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()), - ), - mutbl: hir::Mutability::Not, - })], - tcx.mk_ptr(ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }), + vec![Ty::new_ptr( + tcx, + ty::TypeAndMut { + ty: Ty::new_adt( + tcx, + tcx.adt_def(option_def_id), + tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()), + ), + mutbl: hir::Mutability::Not, + }, + )], + Ty::new_ptr(tcx, ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }), ) } sym::ptr_mask => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), tcx.types.usize, ], - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), sym::copy | sym::copy_nonoverlapping => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), tcx.types.usize, ], - tcx.mk_unit(), + Ty::new_unit(tcx), ), sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), tcx.types.usize, ], - tcx.mk_unit(), + Ty::new_unit(tcx), ), sym::write_bytes | sym::volatile_set_memory => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), tcx.types.u8, tcx.types.usize, ], - tcx.mk_unit(), + Ty::new_unit(tcx), ), sym::sqrtf32 => (0, vec![tcx.types.f32], tcx.types.f32), sym::sqrtf64 => (0, vec![tcx.types.f64], tcx.types.f64), @@ -321,10 +328,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::roundevenf64 => (0, vec![tcx.types.f64], tcx.types.f64), sym::volatile_load | sym::unaligned_volatile_load => { - (1, vec![tcx.mk_imm_ptr(param(0))], param(0)) + (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)) } sym::volatile_store | sym::unaligned_volatile_store => { - (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()) + (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)) } sym::ctpop @@ -336,28 +343,34 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { | sym::bitreverse => (1, vec![param(0)], param(0)), sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { - (1, vec![param(0), param(0)], tcx.mk_tup(&[param(0), tcx.types.bool])) + (1, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool])) } - sym::ptr_guaranteed_cmp => { - (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.u8) - } + sym::ptr_guaranteed_cmp => ( + 1, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], + tcx.types.u8, + ), sym::const_allocate => { - (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8)) + (0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) } sym::const_deallocate => ( 0, - vec![tcx.mk_mut_ptr(tcx.types.u8), tcx.types.usize, tcx.types.usize], - tcx.mk_unit(), + vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], + Ty::new_unit(tcx), ), - sym::ptr_offset_from => { - (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) - } - sym::ptr_offset_from_unsigned => { - (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.usize) - } + sym::ptr_offset_from => ( + 1, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], + tcx.types.isize, + ), + sym::ptr_offset_from_unsigned => ( + 1, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], + tcx.types.usize, + ), sym::unchecked_div | sym::unchecked_rem | sym::exact_div => { (1, vec![param(0), param(0)], param(0)) } @@ -376,12 +389,14 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { } sym::float_to_int_unchecked => (2, vec![param(0)], param(1)), - sym::assume => (0, vec![tcx.types.bool], tcx.mk_unit()), + sym::assume => (0, vec![tcx.types.bool], Ty::new_unit(tcx)), sym::likely => (0, vec![tcx.types.bool], tcx.types.bool), sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool), - sym::read_via_copy => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)), - sym::write_via_move => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), + sym::read_via_copy => (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), + sym::write_via_move => { + (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)) + } sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( @@ -392,43 +407,47 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; ( 1, - vec![tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0))], - tcx.mk_projection(discriminant_def_id, tcx.mk_substs(&[param(0).into()])), + vec![Ty::new_imm_ref( + tcx, + ty::Region::new_late_bound(tcx, ty::INNERMOST, br), + param(0), + )], + Ty::new_projection(tcx, discriminant_def_id, tcx.mk_substs(&[param(0).into()])), ) } kw::Try => { - let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); + let mut_u8 = Ty::new_mut_ptr(tcx, tcx.types.u8); let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( [mut_u8], - tcx.mk_unit(), + Ty::new_unit(tcx), false, hir::Unsafety::Normal, Abi::Rust, )); let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( [mut_u8, mut_u8], - tcx.mk_unit(), + Ty::new_unit(tcx), false, hir::Unsafety::Normal, Abi::Rust, )); ( 0, - vec![tcx.mk_fn_ptr(try_fn_ty), mut_u8, tcx.mk_fn_ptr(catch_fn_ty)], + vec![Ty::new_fn_ptr(tcx, try_fn_ty), mut_u8, Ty::new_fn_ptr(tcx, catch_fn_ty)], tcx.types.i32, ) } sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) { - Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()), + Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], Ty::new_unit(tcx)), None => bug!("`va_list` language item needed for C-variadic intrinsics"), }, sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) { Some((va_list_ref_ty, va_list_ty)) => { - let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty); - (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit()) + let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty); + (0, vec![va_list_ptr_ty, va_list_ref_ty], Ty::new_unit(tcx)) } None => bug!("`va_list` language item needed for C-variadic intrinsics"), }, @@ -438,11 +457,17 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { None => bug!("`va_list` language item needed for C-variadic intrinsics"), }, - sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), + sym::nontemporal_store => { + (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)) + } sym::raw_eq => { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; - let param_ty = tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0)); + let param_ty = Ty::new_imm_ref( + tcx, + ty::Region::new_late_bound(tcx, ty::INNERMOST, br), + param(0), + ); (1, vec![param_ty; 2], tcx.types.bool) } @@ -451,7 +476,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), sym::vtable_size | sym::vtable_align => { - (0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize) + (0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize) } other => { @@ -470,7 +495,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let param = |n| { let name = Symbol::intern(&format!("P{}", n)); - tcx.mk_ty_param(n, name) + Ty::new_param(tcx, n, name) }; let name = it.ident.name; @@ -512,7 +537,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) sym::simd_fpowi => (1, vec![param(0), tcx.types.i32], param(0)), sym::simd_fma => (1, vec![param(0), param(0), param(0)], param(0)), sym::simd_gather => (3, vec![param(0), param(1), param(2)], param(0)), - sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()), + sym::simd_scatter => (3, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)), sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)), sym::simd_cast @@ -541,7 +566,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) name if name.as_str().starts_with("simd_shuffle") => { match name.as_str()["simd_shuffle".len()..].parse() { Ok(n) => { - let params = vec![param(0), param(0), tcx.mk_array(tcx.types.u32, n)]; + let params = vec![param(0), param(0), Ty::new_array(tcx, tcx.types.u32, n)]; (2, params, param(1)) } Err(_) => { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 3971a4c01..ce2da7cb1 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -188,7 +188,7 @@ fn missing_items_err( full_impl_span: Span, ) { let missing_items = - missing_items.iter().filter(|trait_item| tcx.opt_rpitit_info(trait_item.def_id).is_none()); + missing_items.iter().filter(|trait_item| trait_item.opt_rpitit_info.is_none()); let missing_items_msg = missing_items .clone() @@ -296,7 +296,7 @@ fn default_body_is_unstable( /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, - predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>, + predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, ) -> (String, String) { let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default(); let mut projections = vec![]; @@ -304,7 +304,7 @@ fn bounds_from_generic_predicates<'tcx>( debug!("predicate {:?}", predicate); let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + ty::ClauseKind::Trait(trait_predicate) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); if Some(def_id) != tcx.lang_items().sized_trait() { @@ -313,7 +313,7 @@ fn bounds_from_generic_predicates<'tcx>( entry.push(trait_predicate.def_id()); } } - ty::PredicateKind::Clause(ty::Clause::Projection(projection_pred)) => { + ty::ClauseKind::Projection(projection_pred) => { projections.push(bound_predicate.rebind(projection_pred)); } _ => {} @@ -362,7 +362,7 @@ fn fn_sig_suggestion<'tcx>( tcx: TyCtxt<'tcx>, sig: ty::FnSig<'tcx>, ident: Ident, - predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>, + predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, assoc: ty::AssocItem, ) -> String { let args = sig @@ -403,7 +403,30 @@ fn fn_sig_suggestion<'tcx>( .flatten() .collect::<Vec<String>>() .join(", "); - let output = sig.output(); + let mut output = sig.output(); + + let asyncness = if tcx.asyncness(assoc.def_id).is_async() { + output = if let ty::Alias(_, alias_ty) = *output.kind() { + tcx.explicit_item_bounds(alias_ty.def_id) + .subst_iter_copied(tcx, alias_ty.substs) + .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty()) + .unwrap_or_else(|| { + span_bug!( + ident.span, + "expected async fn to have `impl Future` output, but it returns {output}" + ) + }) + } else { + span_bug!( + ident.span, + "expected async fn to have `impl Future` output, but it returns {output}" + ) + }; + "async " + } else { + "" + }; + let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; let unsafety = sig.unsafety.prefix_str(); @@ -414,7 +437,9 @@ fn fn_sig_suggestion<'tcx>( // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. - format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}") + format!( + "{unsafety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}" + ) } pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { @@ -443,19 +468,16 @@ fn suggestion_signature<'tcx>( ); match assoc.kind { - ty::AssocKind::Fn => { - // We skip the binder here because the binder would deanonymize all - // late-bound regions, and we don't want method signatures to show up - // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound - // regions just fine, showing `fn(&MyType)`. - fn_sig_suggestion( - tcx, - tcx.fn_sig(assoc.def_id).subst(tcx, substs).skip_binder(), - assoc.ident(tcx), - tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), - assoc, - ) - } + ty::AssocKind::Fn => fn_sig_suggestion( + tcx, + tcx.liberate_late_bound_regions( + assoc.def_id, + tcx.fn_sig(assoc.def_id).subst(tcx, substs), + ), + assoc.ident(tcx), + tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), + assoc, + ), ty::AssocKind::Type => { let (generics, where_clauses) = bounds_from_generic_predicates( tcx, diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 6ab5556e9..5bd6fcb96 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -392,7 +392,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // Manually recurse over closures and inline consts, because they are the only // case of nested bodies that share the parent environment. hir::ExprKind::Closure(&hir::Closure { body, .. }) - | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => { + | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => { let body = visitor.tcx.hir().body(body); visitor.visit_body(body); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b403ee96b..d4748b7ef 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -15,7 +15,7 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::query::Providers; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ - self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, + self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_middle::ty::{GenericArgKind, InternalSubsts}; @@ -81,7 +81,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { self.tcx(), cause, param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))), )); } } @@ -105,7 +105,12 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( } f(&mut wfcx); - let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id); + 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 implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types); let errors = wfcx.select_all_or_error(); @@ -217,10 +222,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { check_item_fn(tcx, def_id, item.ident, item.span, sig.decl); } hir::ItemKind::Static(ty, ..) => { - check_item_type(tcx, def_id, ty.span, false); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); } hir::ItemKind::Const(ty, ..) => { - check_item_type(tcx, def_id, ty.span, false); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); } hir::ItemKind::Struct(_, ast_generics) => { check_type_defn(tcx, item, false); @@ -242,6 +247,12 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { } // `ForeignItem`s are handled separately. hir::ItemKind::ForeignMod { .. } => {} + hir::ItemKind::TyAlias(hir_ty, ..) => { + if tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() { + // Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);` + check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); + } + } _ => {} } } @@ -258,7 +269,9 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { hir::ForeignItemKind::Fn(decl, ..) => { check_item_fn(tcx, def_id, item.ident, item.span, decl) } - hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, def_id, ty.span, true), + hir::ForeignItemKind::Static(ty, ..) => { + check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail) + } hir::ForeignItemKind::Type => (), } } @@ -314,7 +327,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // Gather the bounds with which all other items inside of this trait constrain the GAT. // This is calculated by taking the intersection of the bounds that each item // constrains the GAT with individually. - let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None; + let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None; for item in associated_items { let item_def_id = item.id.owner_id; // Skip our own GAT, since it does not constrain itself at all. @@ -411,21 +424,17 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let mut unsatisfied_bounds: Vec<_> = required_bounds .into_iter() .filter(|clause| match clause.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( - a, - b, - ))) => !region_known_to_outlive( - tcx, - gat_def_id.def_id, - param_env, - &FxIndexSet::default(), - a, - b, - ), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - a, - b, - ))) => !ty_known_to_outlive( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => { + !region_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.def_id, param_env, @@ -433,7 +442,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe a, b, ), - _ => bug!("Unexpected PredicateKind"), + _ => bug!("Unexpected ClauseKind"), }) .map(|clause| clause.to_string()) .collect(); @@ -481,7 +490,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe fn augment_param_env<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - new_predicates: Option<&FxHashSet<ty::Predicate<'tcx>>>, + new_predicates: Option<&FxHashSet<ty::Clause<'tcx>>>, ) -> ty::ParamEnv<'tcx> { let Some(new_predicates) = new_predicates else { return param_env; @@ -491,7 +500,7 @@ fn augment_param_env<'tcx>( return param_env; } - let bounds = tcx.mk_predicates_from_iter( + let bounds = tcx.mk_clauses_from_iter( param_env.caller_bounds().iter().chain(new_predicates.iter().cloned()), ); // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this @@ -517,7 +526,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( wf_tys: &FxIndexSet<Ty<'tcx>>, gat_def_id: LocalDefId, gat_generics: &'tcx ty::Generics, -) -> Option<FxHashSet<ty::Predicate<'tcx>>> { +) -> Option<FxHashSet<ty::Clause<'tcx>>> { // The bounds we that we would require from `to_check` let mut bounds = FxHashSet::default(); @@ -552,22 +561,24 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( // our example, the type was `Self`, which will also be // `Self` in the GAT. let ty_param = gat_generics.param_at(*ty_idx, tcx); - let ty_param = tcx.mk_ty_param(ty_param.index, ty_param.name); + let ty_param = Ty::new_param(tcx, ty_param.index, ty_param.name); // Same for the region. In our example, 'a corresponds // to the 'me parameter. let region_param = gat_generics.param_at(*region_a_idx, tcx); - let region_param = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: region_param.def_id, - index: region_param.index, - name: region_param.name, - }); + let region_param = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: region_param.def_id, + index: region_param.index, + name: region_param.name, + }, + ); // The predicate we expect to see. (In our example, // `Self: 'me`.) - let clause = ty::PredicateKind::Clause(ty::Clause::TypeOutlives( - ty::OutlivesPredicate(ty_param, region_param), - )); - let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); - bounds.insert(clause); + bounds.insert( + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param)) + .to_predicate(tcx), + ); } } @@ -593,24 +604,32 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. let region_a_param = gat_generics.param_at(*region_a_idx, tcx); - let region_a_param = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: region_a_param.def_id, - index: region_a_param.index, - name: region_a_param.name, - }); + let region_a_param = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: region_a_param.def_id, + index: region_a_param.index, + name: region_a_param.name, + }, + ); // Same for the region. let region_b_param = gat_generics.param_at(*region_b_idx, tcx); - let region_b_param = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: region_b_param.def_id, - index: region_b_param.index, - name: region_b_param.name, - }); + let region_b_param = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: region_b_param.def_id, + index: region_b_param.index, + name: region_b_param.name, + }, + ); // The predicate we expect to see. - let clause = ty::PredicateKind::Clause(ty::Clause::RegionOutlives( - ty::OutlivesPredicate(region_a_param, region_b_param), - )); - let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); - bounds.insert(clause); + bounds.insert( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( + region_a_param, + region_b_param, + )) + .to_predicate(tcx), + ); } } } @@ -820,83 +839,20 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { let ty = tcx.type_of(param.def_id).subst_identity(); if tcx.features().adt_const_params { - if let Some(non_structural_match_ty) = - traits::search_for_adt_const_param_violation(param.span, tcx, ty) - { - // We use the same error code in both branches, because this is really the same - // issue: we just special-case the message for type parameters to make it - // clearer. - match non_structural_match_ty.kind() { - ty::Param(_) => { - // Const parameters may not have type parameters as their types, - // because we cannot be sure that the type parameter derives `PartialEq` - // and `Eq` (just implementing them is not enough for `structural_match`). - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \ - used as the type of a const parameter", - ) - .span_label( - hir_ty.span, - format!("`{ty}` may not derive both `PartialEq` and `Eq`"), - ) - .note( - "it is not currently possible to use a type parameter as the type of a \ - const parameter", - ) - .emit(); - } - ty::Float(_) => { - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "`{ty}` is forbidden as the type of a const generic parameter", - ) - .note("floats do not derive `Eq` or `Ord`, which are required for const parameters") - .emit(); - } - ty::FnPtr(_) => { - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "using function pointers as const generic parameters is forbidden", - ) - .emit(); - } - ty::RawPtr(_) => { - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "using raw pointers as const generic parameters is forbidden", - ) - .emit(); - } - _ => { - let mut diag = struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \ - the type of a const parameter", - non_structural_match_ty, - ); - - if ty == non_structural_match_ty { - diag.span_label( - hir_ty.span, - format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"), - ); - } - - diag.emit(); - } - } - } + enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { + let trait_def_id = + tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)); + wfcx.register_bound( + ObligationCause::new( + hir_ty.span, + param.def_id, + ObligationCauseCode::ConstParam(ty), + ), + wfcx.param_env, + ty, + trait_def_id, + ); + }); } else { let err_ty_str; let mut is_ptr = true; @@ -1025,7 +981,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // intermediate types must be sized. let needs_drop_copy = || { packed && { - let ty = tcx.type_of(variant.fields.raw.last().unwrap().did).subst_identity(); + let ty = tcx.type_of(variant.tail().did).subst_identity(); let ty = tcx.erase_regions(ty); if ty.has_infer() { tcx.sess @@ -1078,9 +1034,9 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b tcx, cause, wfcx.param_env, - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable( ty::Const::from_anon_const(tcx, discr_def_id.expect_local()), - )), + ))), )); } } @@ -1133,7 +1089,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - normalized_bound, + normalized_bound.as_predicate(), bound_span, ) }); @@ -1154,20 +1110,32 @@ fn check_item_fn( }) } -fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) { +enum UnsizedHandling { + Forbid, + Allow, + AllowIfForeignTail, +} + +fn check_item_type( + tcx: TyCtxt<'_>, + item_id: LocalDefId, + ty_span: Span, + unsized_handling: UnsizedHandling, +) { debug!("check_item_type: {:?}", item_id); enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { let ty = tcx.type_of(item_id).subst_identity(); let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); - let mut forbid_unsized = true; - if allow_foreign_ty { - let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env); - if let ty::Foreign(_) = tail.kind() { - forbid_unsized = false; + let forbid_unsized = match unsized_handling { + UnsizedHandling::Forbid => true, + UnsizedHandling::Allow => false, + UnsizedHandling::AllowIfForeignTail => { + let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env); + !matches!(tail.kind(), ty::Foreign(_)) } - } + }; wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into()); if forbid_unsized { @@ -1398,7 +1366,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count).is_break(); - let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs); + let substituted_pred = ty::EarlyBinder::bind(pred).subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region @@ -1441,7 +1409,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id infcx, wfcx.param_env.without_const(), wfcx.body_def_id, - p, + p.as_predicate(), sp, ) }); @@ -1503,7 +1471,7 @@ fn check_fn_or_method<'tcx>( let span = tcx.def_span(def_id); let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None; let mut inputs = sig.inputs().iter().skip(if has_implicit_self { 1 } else { 0 }); - // Check that the argument is a tuple + // Check that the argument is a tuple and is sized if let Some(ty) = inputs.next() { wfcx.register_bound( ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall), @@ -1511,6 +1479,12 @@ fn check_fn_or_method<'tcx>( *ty, tcx.require_lang_item(hir::LangItem::Tuple, Some(span)), ); + wfcx.register_bound( + ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall), + wfcx.param_env, + *ty, + tcx.require_lang_item(hir::LangItem::Sized, Some(span)), + ); } else { tcx.sess.span_err( hir_decl.inputs.last().map_or(span, |input| input.span), @@ -1572,13 +1546,13 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind() && self.seen.insert(unshifted_opaque_ty.def_id) && let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local() - && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty() - && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin + && let origin = tcx.opaque_type_origin(opaque_def_id) + && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = origin && source == self.fn_def_id { let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| { match re.kind() { - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) => re, + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) | ty::ReStatic => re, r => bug!("unexpected region: {r:?}"), } }); @@ -1591,7 +1565,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { self.wfcx.infcx, self.wfcx.param_env, self.wfcx.body_def_id, - bound, + bound.as_predicate(), bound_span, )); // Set the debruijn index back to innermost here, since we already eagerly @@ -1799,9 +1773,11 @@ fn check_variances_for_type_defn<'tcx>( item: &hir::Item<'tcx>, hir_generics: &hir::Generics<'_>, ) { - let ty = tcx.type_of(item.owner_id).subst_identity(); - if tcx.has_error_field(ty) { - return; + let identity_substs = ty::InternalSubsts::identity_for_item(tcx, item.owner_id); + for field in tcx.adt_def(item.owner_id).all_fields() { + if field.ty(tcx, identity_substs).references_error() { + return; + } } let ty_predicates = tcx.predicates_of(item.owner_id); @@ -1902,7 +1878,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { // We lower empty bounds like `Vec<dyn Copy>:` as // `WellFormed(Vec<dyn Copy>)`, which will later get checked by // regular WF checking - if let ty::PredicateKind::WellFormed(..) = pred.kind().skip_binder() { + if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() { continue; } // Match the existing behavior. diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index a98d8e171..79cc43edf 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -336,15 +336,17 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; - check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) + check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty)) } (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => { let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; - check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) + check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty)) } - (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)), + (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => { + check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty)) + } (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) if def_a.is_struct() && def_b.is_struct() => @@ -571,7 +573,7 @@ fn infringing_fields_error( .or_default() .push(error.obligation.cause.span); } - if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Positive, .. diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index bd6252344..3bd293126 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -140,7 +140,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { impl1_def_id: DefId, impl2_def_id: DefId, ) { - traits::overlapping_impls( + let maybe_overlap = traits::overlapping_impls( self.tcx, impl1_def_id, impl2_def_id, @@ -148,11 +148,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> { // inherent impls without warning. SkipLeakCheck::Yes, overlap_mode, - ) - .map_or(true, |overlap| { + ); + + if let Some(overlap) = maybe_overlap { self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap); - false - }); + } } fn check_item(&mut self, id: hir::ItemId) { diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 4524b87a4..5097f4360 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -10,7 +10,6 @@ use rustc_errors::{error_code, struct_span_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_span::sym; use rustc_trait_selection::traits; mod builtin; @@ -44,7 +43,7 @@ fn enforce_trait_manually_implementable( let impl_header_span = tcx.def_span(impl_def_id); // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` - if tcx.has_attr(trait_def_id, sym::rustc_deny_explicit_impl) { + if tcx.trait_def(trait_def_id).deny_explicit_impl { let trait_name = tcx.item_name(trait_def_id); let mut err = struct_span_err!( tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 23beacd2a..025bab140 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -200,35 +200,32 @@ fn do_orphan_check_impl<'tcx>( NonlocalImpl::DisallowOther, ), - // trait Id { type This: ?Sized; } - // impl<T: ?Sized> Id for T { - // type This = T; - // } - // impl<T: ?Sized> AutoTrait for <T as Id>::This {} - ty::Alias(AliasKind::Projection, _) => ( - LocalImpl::Disallow { problematic_kind: "associated type" }, - NonlocalImpl::DisallowOther, - ), - - // ``` - // struct S<T>(T); - // impl<T: ?Sized> S<T> { - // type This = T; - // } - // impl<T: ?Sized> AutoTrait for S<T>::This {} - // ``` - // FIXME(inherent_associated_types): The example code above currently leads to a cycle - ty::Alias(AliasKind::Inherent, _) => ( - LocalImpl::Disallow { problematic_kind: "associated type" }, - NonlocalImpl::DisallowOther, - ), - - // type Opaque = impl Trait; - // impl AutoTrait for Opaque {} - ty::Alias(AliasKind::Opaque, _) => ( - LocalImpl::Disallow { problematic_kind: "opaque type" }, - NonlocalImpl::DisallowOther, - ), + ty::Alias(kind, _) => { + let problematic_kind = match kind { + // trait Id { type This: ?Sized; } + // impl<T: ?Sized> Id for T { + // type This = T; + // } + // impl<T: ?Sized> AutoTrait for <T as Id>::This {} + AliasKind::Projection => "associated type", + // type Foo = (impl Sized, bool) + // impl AutoTrait for Foo {} + AliasKind::Weak => "type alias", + // type Opaque = impl Trait; + // impl AutoTrait for Opaque {} + AliasKind::Opaque => "opaque type", + // ``` + // struct S<T>(T); + // impl<T: ?Sized> S<T> { + // type This = T; + // } + // impl<T: ?Sized> AutoTrait for S<T>::This {} + // ``` + // FIXME(inherent_associated_types): The example code above currently leads to a cycle + AliasKind::Inherent => "associated type", + }; + (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther) + } ty::Bool | ty::Char @@ -346,7 +343,7 @@ fn emit_orphan_check_error<'tcx>( // That way if we had `Vec<MyType>`, we will properly attribute the // problem to `Vec<T>` and avoid confusing the user if they were to see // `MyType` in the error. - ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()), + ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()), _ => ty, }; let msg = |ty: &str, postfix: &str| { @@ -608,7 +605,9 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: } let self_ty_root = match self_ty.kind() { - ty::Adt(def, _) => tcx.mk_adt(*def, InternalSubsts::identity_for_item(tcx, def.did())), + ty::Adt(def, _) => { + Ty::new_adt(tcx, *def, InternalSubsts::identity_for_item(tcx, def.did())) + } _ => unimplemented!("unexpected self ty {:?}", self_ty), }; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index ca0d5509c..f47df4f21 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -380,7 +380,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - self.tcx().ty_error_with_message(span, "bad placeholder type") + Ty::new_error_with_message(self.tcx(), span, "bad placeholder type") } fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { @@ -390,7 +390,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { // left alone. r => bug!("unexpected region: {r:?}"), }); - self.tcx().const_error_with_message(ty, span, "bad placeholder constant") + ty::Const::new_error_with_message(self.tcx(), ty, span, "bad placeholder constant") } fn projected_ty_from_poly_trait_ref( @@ -407,7 +407,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { item_segment, trait_ref.substs, ); - self.tcx().mk_projection(item_def_id, item_substs) + Ty::new_projection(self.tcx(), item_def_id, item_substs) } else { // There are no late-bound regions; we can just ignore the binder. let (mut mpart_sugg, mut inferred_sugg) = (None, None); @@ -440,7 +440,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx.replace_late_bound_regions_uncached( poly_trait_ref, |_| { - self.tcx.mk_re_early_bound(ty::EarlyBoundRegion { + ty::Region::new_early_bound(self.tcx, ty::EarlyBoundRegion { def_id: item_def_id, index: 0, name: Symbol::intern(<_name), @@ -471,14 +471,15 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } _ => {} } - self.tcx().ty_error(self.tcx().sess.emit_err( - errors::AssociatedTypeTraitUninferredGenericParams { + Ty::new_error( + self.tcx(), + self.tcx().sess.emit_err(errors::AssociatedTypeTraitUninferredGenericParams { span, inferred_sugg, bound, mpart_sugg, - }, - )) + }), + ) } } @@ -666,17 +667,15 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { tcx.ensure().fn_sig(def_id); } - hir::TraitItemKind::Const(.., Some(_)) => { - tcx.ensure().type_of(def_id); - } - - hir::TraitItemKind::Const(hir_ty, _) => { + hir::TraitItemKind::Const(ty, body_id) => { tcx.ensure().type_of(def_id); - // Account for `const C: _;`. - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_trait_item(trait_item); - if !tcx.sess.diagnostic().has_stashed_diagnostic(hir_ty.span, StashKey::ItemNoType) { - placeholder_type_error(tcx, None, visitor.0, false, None, "constant"); + if !tcx.sess.diagnostic().has_stashed_diagnostic(ty.span, StashKey::ItemNoType) + && !(is_suggestable_infer_ty(ty) && body_id.is_some()) + { + // Account for `const C: _;`. + let mut visitor = HirPlaceholderCollector::default(); + visitor.visit_trait_item(trait_item); + placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant"); } } @@ -721,7 +720,14 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); } - hir::ImplItemKind::Const(..) => {} + hir::ImplItemKind::Const(ty, _) => { + // Account for `const T: _ = ..;` + if !is_suggestable_infer_ty(ty) { + let mut visitor = HirPlaceholderCollector::default(); + visitor.visit_impl_item(impl_item); + placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant"); + } + } } } @@ -941,7 +947,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { match item { Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => { - if !tcx.impl_defaultness(item.id.owner_id).has_value() { + if !tcx.defaultness(item.id.owner_id).has_value() { tcx.sess.emit_err(errors::FunctionNotHaveDefaultImplementation { span: item.span, note_span: attr_span, @@ -986,6 +992,50 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { no_dups.then_some(list) }); + let mut deny_explicit_impl = false; + let mut implement_via_object = true; + if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) { + deny_explicit_impl = true; + let mut seen_attr = false; + for meta in attr.meta_item_list().iter().flatten() { + if let Some(meta) = meta.meta_item() + && meta.name_or_empty() == sym::implement_via_object + && let Some(lit) = meta.name_value_literal() + { + if seen_attr { + tcx.sess.span_err( + meta.span, + "duplicated `implement_via_object` meta item", + ); + } + seen_attr = true; + + match lit.symbol { + kw::True => { + implement_via_object = true; + } + kw::False => { + implement_via_object = false; + } + _ => { + tcx.sess.span_err( + meta.span, + format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol), + ); + } + } + } else { + tcx.sess.span_err( + meta.span(), + format!("unknown meta item passed to `rustc_deny_explicit_impl` {:?}", meta), + ); + } + } + if !seen_attr { + tcx.sess.span_err(attr.span, "missing `implement_via_object` meta item"); + } + } + ty::TraitDef { def_id: def_id.to_def_id(), unsafety, @@ -996,6 +1046,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { skip_array_during_method_dispatch, specialization_kind, must_implement_one_of, + implement_via_object, + deny_explicit_impl, } } @@ -1124,7 +1176,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig< bug!("unexpected sort of node in fn_sig(): {:?}", x); } }; - ty::EarlyBinder(output) + ty::EarlyBinder::bind(output) } fn infer_return_ty_for_fn_sig<'tcx>( @@ -1188,7 +1240,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( } else { ty::Binder::dummy(tcx.mk_fn_sig( fn_sig.inputs().iter().copied(), - tcx.ty_error(guar), + Ty::new_error(tcx, guar), fn_sig.c_variadic, fn_sig.unsafety, fn_sig.abi, @@ -1277,11 +1329,11 @@ fn suggest_impl_trait<'tcx>( { continue; } - let ocx = ObligationCtxt::new_in_snapshot(&infcx); + let ocx = ObligationCtxt::new(&infcx); let item_ty = ocx.normalize( &ObligationCause::misc(span, def_id), param_env, - tcx.mk_projection(assoc_item_def_id, substs), + Ty::new_projection(tcx, assoc_item_def_id, substs), ); // FIXME(compiler-errors): We may benefit from resolving regions here. if ocx.select_where_possible().is_empty() @@ -1312,7 +1364,7 @@ fn impl_trait_ref( check_impl_constness(tcx, impl_.constness, ast_trait_ref), ) }) - .map(ty::EarlyBinder) + .map(ty::EarlyBinder::bind) } fn check_impl_constness( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index ed60998ec..ccc9f8084 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; @@ -50,7 +50,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // We do not allow generic parameters in anon consts if we are inside // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed. None - } else if tcx.lazy_normalization() { + } else if tcx.features().generic_const_exprs { let parent_node = tcx.hir().get_parent(hir_id); if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node && constant.hir_id == hir_id @@ -101,6 +101,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, + host_effect_index: None, }; } else { // HACK(eddyb) this provides the correct generics when @@ -123,9 +124,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { { Some(parent_def_id.to_def_id()) } - Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { - Some(tcx.typeck_root_def_id(def_id.to_def_id())) - } // Exclude `GlobalAsm` here which cannot have generics. Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) if asm.operands.iter().any(|(op, _op_sp)| match op { @@ -142,11 +140,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } } - Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { + Node::ConstBlock(_) + | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { Some(tcx.typeck_root_def_id(def_id.to_def_id())) } Node::Item(item) => match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { + ItemKind::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id), in_trait, @@ -228,10 +227,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let has_self = opt_self.is_some(); let mut parent_has_self = false; let mut own_start = has_self as u32; + let mut host_effect_index = None; let parent_count = parent_def_id.map_or(0, |def_id| { let generics = tcx.generics_of(def_id); assert!(!has_self); parent_has_self = generics.has_self; + host_effect_index = generics.host_effect_index; own_start = generics.count() as u32; generics.parent_count + generics.params.len() }); @@ -253,11 +254,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; - let mut i = 0; + let mut i: u32 = 0; let mut next_index = || { let prev = i; i += 1; - prev as u32 + type_start + prev + type_start }; const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ @@ -297,7 +298,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }) } GenericParamKind::Const { default, .. } => { - if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { + let is_host_param = tcx.has_attr(param.def_id, sym::rustc_host); + + if !matches!(allow_defaults, Defaults::Allowed) + && default.is_some() + // `rustc_host` effect params are allowed to have defaults. + && !is_host_param + { tcx.sess.span_err( param.span, "defaults for const parameters are only allowed in \ @@ -305,8 +312,18 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ); } + let index = next_index(); + + if is_host_param { + if let Some(idx) = host_effect_index { + bug!("parent also has host effect param? index: {idx}, def: {def_id:?}"); + } + + host_effect_index = Some(parent_count + index as usize); + } + Some(ty::GenericParamDef { - index: next_index(), + index, name: param.name.ident().name, def_id: param.def_id.to_def_id(), pure_wrt_drop: param.pure_wrt_drop, @@ -339,17 +356,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } // provide junk type parameter defs for const blocks. - if let Node::AnonConst(_) = node { - let parent_node = tcx.hir().get_parent(hir_id); - if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node { - params.push(ty::GenericParamDef { - index: next_index(), - name: Symbol::intern("<const_ty>"), - def_id: def_id.to_def_id(), - pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, - }); - } + if let Node::ConstBlock(_) = node { + params.push(ty::GenericParamDef { + index: next_index(), + name: Symbol::intern("<const_ty>"), + def_id: def_id.to_def_id(), + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, + }); } let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); @@ -361,6 +375,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: has_self || parent_has_self, has_late_bound_regions: has_late_bound_regions(tcx, node), + host_effect_index, } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 948b903e5..57f74172e 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -1,5 +1,5 @@ use super::ItemCtxt; -use crate::astconv::{AstConv, OnlySelfBounds}; +use crate::astconv::{AstConv, PredicateFilter}; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; @@ -19,32 +19,34 @@ fn associated_type_bounds<'tcx>( assoc_item_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, -) -> &'tcx [(ty::Predicate<'tcx>, Span)] { - let item_ty = tcx.mk_projection( +) -> &'tcx [(ty::Clause<'tcx>, Span)] { + let item_ty = Ty::new_projection( + tcx, assoc_item_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); let icx = ItemCtxt::new(tcx, assoc_item_def_id); - let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false)); + let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All); // Associated types are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { - match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => tr.self_ty() == item_ty, - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { - proj.projection_ty.self_ty() == item_ty - } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => outlives.0 == item_ty, + let bounds_from_parent = trait_predicates + .predicates + .iter() + .copied() + .filter(|(pred, _)| match pred.kind().skip_binder() { + ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty, + ty::ClauseKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty, + ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty, _ => false, - } - }); + }) + .map(|(clause, span)| (clause, span)); - let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent)); + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), @@ -64,33 +66,34 @@ fn opaque_type_bounds<'tcx>( ast_bounds: &'tcx [hir::GenericBound<'tcx>], item_ty: Ty<'tcx>, span: Span, -) -> &'tcx [(ty::Predicate<'tcx>, Span)] { +) -> &'tcx [(ty::Clause<'tcx>, Span)] { ty::print::with_no_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); - let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false)); + let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All); // Opaque types are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); debug!(?bounds); - tcx.arena.alloc_from_iter(bounds.predicates()) + tcx.arena.alloc_from_iter(bounds.clauses()) }) } pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> { +) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { match tcx.opt_rpitit_info(def_id.to_def_id()) { // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return ty::EarlyBinder(opaque_type_bounds( + return ty::EarlyBinder::bind(opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, - tcx.mk_projection( + Ty::new_projection( + tcx, def_id.to_def_id(), ty::InternalSubsts::identity_for_item(tcx, def_id), ), @@ -116,25 +119,23 @@ pub(super) fn explicit_item_bounds( }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { - tcx.mk_projection(def_id.to_def_id(), substs) + Ty::new_projection(tcx, def_id.to_def_id(), substs) } else { - tcx.mk_opaque(def_id.to_def_id(), substs) + Ty::new_opaque(tcx, def_id.to_def_id(), substs) }; opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } + hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], _ => bug!("item_bounds called on {:?}", def_id), }; - ty::EarlyBinder(bounds) + ty::EarlyBinder::bind(bounds) } pub(super) fn item_bounds( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> { +) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { tcx.explicit_item_bounds(def_id).map_bound(|bounds| { - tcx.mk_predicates_from_iter(util::elaborate( - tcx, - bounds.iter().map(|&(bound, _span)| bound), - )) + tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound))) }) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e5b5dae55..129366641 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,8 +1,8 @@ -use crate::astconv::{AstConv, OnlySelfBounds}; +use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter}; use crate::bounds::Bounds; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; -use hir::{HirId, Node}; +use hir::{HirId, Lifetime, Node}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -10,9 +10,9 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{GenericPredicates, ToPredicate}; +use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{Span, Symbol, 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 @@ -62,6 +62,67 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; + match tcx.opt_rpitit_info(def_id.to_def_id()) { + Some(ImplTraitInTraitData::Trait { opaque_def_id, fn_def_id }) => { + let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local()); + let opaque_ty_node = tcx.hir().get(opaque_ty_id); + let Node::Item(&Item { kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }), .. }) = opaque_ty_node else { + bug!("unexpected {opaque_ty_node:?}") + }; + + let mut predicates = Vec::new(); + + // RPITITs should inherit the predicates of their parent. This is + // both to ensure that the RPITITs are only instantiated when the + // parent predicates would hold, and also so that the param-env + // inherits these predicates as assumptions. + let identity_substs = InternalSubsts::identity_for_item(tcx, def_id); + predicates.extend( + tcx.explicit_predicates_of(fn_def_id).instantiate_own(tcx, identity_substs), + ); + + // We also install bidirectional outlives predicates for the RPITIT + // to keep the duplicates lifetimes from opaque lowering in sync. + compute_bidirectional_outlives_predicates( + tcx, + def_id, + lifetime_mapping.iter().map(|(lifetime, def_id)| { + (*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span)) + }), + tcx.generics_of(def_id.to_def_id()), + &mut predicates, + ); + + return ty::GenericPredicates { + parent: Some(tcx.parent(def_id.to_def_id())), + predicates: tcx.arena.alloc_from_iter(predicates), + }; + } + + Some(ImplTraitInTraitData::Impl { fn_def_id }) => { + let assoc_item = tcx.associated_item(def_id); + let trait_assoc_predicates = + tcx.explicit_predicates_of(assoc_item.trait_item_def_id.unwrap()); + + let impl_assoc_identity_substs = InternalSubsts::identity_for_item(tcx, def_id); + let impl_def_id = tcx.parent(fn_def_id); + let impl_trait_ref_substs = + tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity().substs; + + let impl_assoc_substs = + impl_assoc_identity_substs.rebase_onto(tcx, impl_def_id, impl_trait_ref_substs); + + let impl_predicates = trait_assoc_predicates.instantiate_own(tcx, impl_assoc_substs); + + return ty::GenericPredicates { + parent: Some(impl_def_id), + predicates: tcx.arena.alloc_from_iter(impl_predicates), + }; + } + + None => {} + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); @@ -75,7 +136,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We use an `IndexSet` to preserve order of insertion. // Preserving the order of insertion is important here so as not to break UI tests. - let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default(); + let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default(); let ast_generics = match node { Node::TraitItem(item) => item.generics, @@ -125,8 +186,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen if let Some(self_bounds) = is_trait { predicates.extend( icx.astconv() - .compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false)) - .predicates(), + .compute_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All) + .clauses(), ); } @@ -175,22 +236,24 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen param.span, ); trace!(?bounds); - predicates.extend(bounds.predicates()); + predicates.extend(bounds.clauses()); trace!(?predicates); } GenericParamKind::Const { .. } => { let name = param.name.ident().name; let param_const = ty::ParamConst::new(index, name); - let ct_ty = tcx.type_of(param.def_id.to_def_id()).subst_identity(); + let ct_ty = tcx + .type_of(param.def_id.to_def_id()) + .no_bound_vars() + .expect("const parameters cannot be generic"); - let ct = tcx.mk_const(param_const, ct_ty); + let ct = ty::Const::new_param(tcx, param_const, ct_ty); - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::ConstArgHasType(ct, ct_ty), - )) - .to_predicate(tcx); - predicates.insert((predicate, param.span)); + predicates.insert(( + ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx), + param.span, + )); index += 1; } @@ -219,7 +282,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } else { let span = bound_pred.bounded_ty.span; let predicate = ty::Binder::bind_with_vars( - ty::PredicateKind::WellFormed(ty.into()), + ty::ClauseKind::WellFormed(ty.into()), bound_vars, ); predicates.insert((predicate.to_predicate(tcx), span)); @@ -234,7 +297,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_vars, OnlySelfBounds(false), ); - predicates.extend(bounds.predicates()); + predicates.extend(bounds.clauses()); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -246,11 +309,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } _ => bug!(), }; - let pred = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2)), - )) - .to_predicate(icx.tcx); - + let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) + .to_predicate(icx.tcx); (pred, span) })) } @@ -293,39 +353,22 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bug!("unexpected {opaque_ty_node:?}") }; debug!(?lifetimes); - for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) { - let hir::GenericArg::Lifetime(arg) = arg else { bug!() }; - let orig_region = icx.astconv().ast_region_to_region(&arg, None); - if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) { - // Only early-bound regions can point to the original generic parameter. - continue; - } - let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue }; - let dup_def = duplicate.def_id.to_def_id(); - - let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() }; - - let dup_region = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: dup_def, - index: dup_index, - name: duplicate.name.ident().name, - }); - predicates.push(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( - ty::OutlivesPredicate(orig_region, dup_region), - ))) - .to_predicate(icx.tcx), - duplicate.span, - )); - predicates.push(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( - ty::OutlivesPredicate(dup_region, orig_region), - ))) - .to_predicate(icx.tcx), - duplicate.span, - )); - } + let lifetime_mapping = std::iter::zip(lifetimes, ast_generics.params) + .map(|(arg, dup)| { + let hir::GenericArg::Lifetime(arg) = arg else { bug!() }; + (**arg, dup) + }) + .filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. })) + .map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span))); + + compute_bidirectional_outlives_predicates( + tcx, + def_id, + lifetime_mapping, + generics, + &mut predicates, + ); debug!(?predicates); } @@ -335,13 +378,53 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } } +/// Opaques have duplicated lifetimes and we need to compute bidirectional outlives predicates to +/// enforce that these lifetimes stay in sync. +fn compute_bidirectional_outlives_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + item_def_id: LocalDefId, + lifetime_mapping: impl Iterator<Item = (Lifetime, (LocalDefId, Symbol, Span))>, + generics: &Generics, + predicates: &mut Vec<(ty::Clause<'tcx>, Span)>, +) { + let icx = ItemCtxt::new(tcx, item_def_id); + + for (arg, (dup_def, name, span)) in lifetime_mapping { + let orig_region = icx.astconv().ast_region_to_region(&arg, None); + if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) { + // There is no late-bound lifetime to actually match up here, since the lifetime doesn't + // show up in the opaque's parent's substs. + continue; + } + + let Some(dup_index) = generics.param_def_id_to_index(icx.tcx, dup_def.to_def_id()) else { bug!() }; + + let dup_region = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { def_id: dup_def.to_def_id(), index: dup_index, name }, + ); + + predicates.push(( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region)) + .to_predicate(tcx), + span, + )); + + predicates.push(( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region)) + .to_predicate(tcx), + span, + )); + } +} + fn const_evaluatable_predicates_of( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> FxIndexSet<(ty::Predicate<'_>, Span)> { +) -> FxIndexSet<(ty::Clause<'_>, Span)> { struct ConstCollector<'tcx> { tcx: TyCtxt<'tcx>, - preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>, + preds: FxIndexSet<(ty::Clause<'tcx>, Span)>, } impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { @@ -349,11 +432,8 @@ fn const_evaluatable_predicates_of( let ct = ty::Const::from_anon_const(self.tcx, c.def_id); if let ty::ConstKind::Unevaluated(_) = ct.kind() { let span = self.tcx.def_span(c.def_id); - self.preds.insert(( - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)) - .to_predicate(self.tcx), - span, - )); + self.preds + .insert((ty::ClauseKind::ConstEvaluatable(ct).to_predicate(self.tcx), span)); } } @@ -441,13 +521,9 @@ pub(super) fn explicit_predicates_of<'tcx>( .iter() .copied() .filter(|(pred, _)| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => !is_assoc_item_ty(tr.self_ty()), - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { - !is_assoc_item_ty(proj.projection_ty.self_ty()) - } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => { - !is_assoc_item_ty(outlives.0) - } + ty::ClauseKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()), + ty::ClauseKind::Projection(proj) => !is_assoc_item_ty(proj.projection_ty.self_ty()), + ty::ClauseKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0), _ => true, }) .collect(); @@ -460,7 +536,7 @@ pub(super) fn explicit_predicates_of<'tcx>( } } } else { - if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { + if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(hir_id); @@ -488,9 +564,7 @@ pub(super) fn explicit_predicates_of<'tcx>( .predicates .into_iter() .filter(|(pred, _)| { - if let ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, _)) = - pred.kind().skip_binder() - { + if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() { match ct.kind() { ty::ConstKind::Param(param_const) => { let defaulted_param_idx = tcx @@ -544,19 +618,6 @@ pub(super) fn explicit_predicates_of<'tcx>( } } -#[derive(Copy, Clone, Debug)] -pub enum PredicateFilter { - /// All predicates may be implied by the trait - All, - - /// Only traits that reference `Self: ..` are implied by the trait - SelfOnly, - - /// Only traits that reference `Self: ..` and define an associated type - /// with the given ident are implied by the trait - SelfThatDefines(Ident), -} - /// Ensures that the super-predicates of the trait with a `DefId` /// of `trait_def_id` are converted and stored. This also ensures that /// the transitive super-predicates are converted. @@ -578,11 +639,15 @@ pub(super) fn implied_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { - if tcx.is_trait_alias(trait_def_id.to_def_id()) { - implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All) - } else { - tcx.super_predicates_of(trait_def_id) - } + implied_predicates_with_filter( + tcx, + trait_def_id.to_def_id(), + if tcx.is_trait_alias(trait_def_id.to_def_id()) { + PredicateFilter::All + } else { + PredicateFilter::SelfAndAssociatedTypeBounds + }, + ) } /// Ensures that the super-predicates of the trait with a `DefId` @@ -615,48 +680,18 @@ pub(super) fn implied_predicates_with_filter( let icx = ItemCtxt::new(tcx, trait_def_id); let self_param_ty = tcx.types.self_param; - let (superbounds, where_bounds_that_match) = match filter { - PredicateFilter::All => ( - // Convert the bounds that follow the colon (or equal in trait aliases) - icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)), - // Also include all where clause bounds - icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - OnlySelfBounds(false), - None, - ), - ), - PredicateFilter::SelfOnly => ( - // Convert the bounds that follow the colon (or equal in trait aliases) - icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)), - // Include where clause bounds for `Self` - icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - OnlySelfBounds(true), - None, - ), - ), - PredicateFilter::SelfThatDefines(assoc_name) => ( - // Convert the bounds that follow the colon (or equal) that reference the associated name - icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name), - // Include where clause bounds for `Self` that reference the associated name - icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - OnlySelfBounds(true), - Some(assoc_name), - ), - ), - }; + let superbounds = icx.astconv().compute_bounds(self_param_ty, bounds, filter); + + let where_bounds_that_match = icx.type_parameter_bounds_in_generics( + generics, + item.owner_id.def_id, + self_param_ty, + filter, + ); // Combine the two lists to form the complete set of superbounds: let implied_bounds = - &*tcx.arena.alloc_from_iter(superbounds.predicates().chain(where_bounds_that_match)); + &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match)); debug!(?implied_bounds); // Now require that immediate supertraits are converted, which will, in @@ -665,7 +700,7 @@ pub(super) fn implied_predicates_with_filter( if matches!(filter, PredicateFilter::SelfOnly) { for &(pred, span) in implied_bounds { debug!("superbound: {:?}", pred); - if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() + if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::ImplPolarity::Positive { tcx.at(span).super_predicates_of(bound.def_id()); @@ -684,6 +719,7 @@ pub(super) fn type_param_predicates( (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident), ) -> ty::GenericPredicates<'_> { use rustc_hir::*; + use rustc_middle::ty::Ty; // In the AST, bounds can derive from two places. Either // written inline like `<T: Foo>` or in a where-clause like @@ -693,7 +729,7 @@ pub(super) fn type_param_predicates( let param_owner = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(param_owner); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)); + let ty = Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)); // Don't look for bounds where the type parameter isn't in scope. let parent = if item_def_id == param_owner { @@ -721,7 +757,7 @@ pub(super) fn type_param_predicates( ItemKind::Fn(.., generics, _) | ItemKind::Impl(&hir::Impl { generics, .. }) | ItemKind::TyAlias(_, generics) - | ItemKind::OpaqueTy(OpaqueTy { + | ItemKind::OpaqueTy(&OpaqueTy { generics, origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. @@ -757,12 +793,11 @@ pub(super) fn type_param_predicates( ast_generics, def_id, ty, - OnlySelfBounds(true), - Some(assoc_name), + PredicateFilter::SelfThatDefines(assoc_name), ) .into_iter() .filter(|(predicate, _)| match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => data.self_ty().is_param(index), + ty::ClauseKind::Trait(data) => data.self_ty().is_param(index), _ => false, }), ); @@ -782,9 +817,8 @@ impl<'tcx> ItemCtxt<'tcx> { ast_generics: &'tcx hir::Generics<'tcx>, param_def_id: LocalDefId, ty: Ty<'tcx>, - only_self_bounds: OnlySelfBounds, - assoc_name: Option<Ident>, - ) -> Vec<(ty::Predicate<'tcx>, Span)> { + filter: PredicateFilter, + ) -> Vec<(ty::Clause<'tcx>, Span)> { let mut bounds = Bounds::default(); for predicate in ast_generics.predicates { @@ -792,9 +826,23 @@ impl<'tcx> ItemCtxt<'tcx> { continue; }; + let (only_self_bounds, assoc_name) = match filter { + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { + (OnlySelfBounds(false), None) + } + PredicateFilter::SelfOnly => (OnlySelfBounds(true), None), + PredicateFilter::SelfThatDefines(assoc_name) => { + (OnlySelfBounds(true), Some(assoc_name)) + } + }; + + // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we + // want to only consider predicates with `Self: ...`, but we don't want + // `OnlySelfBounds(true)` since we want to collect the nested associated + // type bound as well. let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) { ty - } else if !only_self_bounds.0 { + } else if matches!(filter, PredicateFilter::All) { self.to_ty(predicate.bounded_ty) } else { continue; @@ -813,7 +861,7 @@ impl<'tcx> ItemCtxt<'tcx> { ); } - bounds.predicates().collect() + bounds.clauses().collect() } #[instrument(level = "trace", skip(self))] 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 794812a5c..acd0bcd8e 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_session::lint; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::fmt; use crate::errors; @@ -338,7 +338,17 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::TraitRefBoundary { .. } => { // We should only see super trait lifetimes if there is a `Binder` above - assert!(supertrait_bound_vars.is_empty()); + // though this may happen when we call `poly_trait_ref_binder_info` with + // an (erroneous, #113423) associated return type bound in an impl header. + if !supertrait_bound_vars.is_empty() { + self.tcx.sess.delay_span_bug( + DUMMY_SP, + format!( + "found supertrait lifetimes without a binder to append \ + them to: {supertrait_bound_vars:?}" + ), + ); + } break (vec![], BinderScopeType::Normal); } @@ -556,7 +566,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }); } } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { + hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent), generics, .. @@ -1344,12 +1354,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Binder { where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), .. } => { - let mut err = self.tcx.sess.struct_span_err( - lifetime_ref.ident.span, - "`impl Trait` can only mention lifetimes bound at the fn or impl level", - ); - err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here"); - err.emit(); + self.tcx.sess.emit_err(errors::LateBoundInApit::Lifetime { + span: lifetime_ref.ident.span, + param_span: self.tcx.def_span(region_def_id), + }); return; } Scope::Root { .. } => break, @@ -1379,6 +1387,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let mut late_depth = 0; let mut scope = self.scope; let mut crossed_anon_const = false; + let result = loop { match *scope { Scope::Body { s, .. } => { @@ -1446,6 +1455,50 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { return; } + // We may fail to resolve higher-ranked ty/const vars that are mentioned by APIT. + // AST-based resolution does not care for impl-trait desugaring, which are the + // responsibility of lowering. This may create a mismatch between the resolution + // AST found (`param_def_id`) which points to HRTB, and what HIR allows. + // ``` + // fn foo(x: impl for<T> Trait<Assoc = impl Trait2<T>>) {} + // ``` + // + // In such case, walk back the binders to diagnose it properly. + let mut scope = self.scope; + loop { + match *scope { + Scope::Binder { + where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), .. + } => { + let guar = self.tcx.sess.emit_err(match self.tcx.def_kind(param_def_id) { + DefKind::TyParam => errors::LateBoundInApit::Type { + span: self.tcx.hir().span(hir_id), + param_span: self.tcx.def_span(param_def_id), + }, + DefKind::ConstParam => errors::LateBoundInApit::Const { + span: self.tcx.hir().span(hir_id), + param_span: self.tcx.def_span(param_def_id), + }, + kind => { + bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id())) + } + }); + self.map.defs.insert(hir_id, ResolvedArg::Error(guar)); + return; + } + Scope::Root { .. } => break, + Scope::Binder { s, .. } + | Scope::Body { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { + scope = s; + } + } + } + self.tcx.sess.delay_span_bug( self.tcx.hir().span(hir_id), format!("could not resolve {param_def_id:?}"), @@ -1761,7 +1814,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::ClauseKind::Trait(data) => { // The order here needs to match what we would get from `subst_supertrait` let pred_bound_vars = bound_predicate.bound_vars(); let mut all_bound_vars = bound_vars.clone(); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 8e082d3c5..3755342ae 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -16,6 +16,7 @@ mod opaque; fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { use hir::*; + use rustc_middle::ty::Ty; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let Node::AnonConst(_) = tcx.hir().get(hir_id) else { panic!() }; @@ -25,21 +26,15 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let (generics, arg_idx) = match parent_node { // Easy case: arrays repeat expressions. - Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) + Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) if constant.hir_id() == hir_id => { return tcx.types.usize } - Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { + 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) } - Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. }) - if anon_const.hir_id == hir_id => - { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - return substs.as_inline_const().ty() - } Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) if asm.operands.iter().any(|(op, _op_sp)| match op { @@ -73,7 +68,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { ) => { let Some(trait_def_id) = trait_ref.trait_def_id() else { - return tcx.ty_error_with_message(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( @@ -85,7 +80,7 @@ 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. - tcx.ty_error_with_message(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") } } @@ -105,7 +100,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // arm would handle this. // // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU - Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { + Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { // Find the Item containing the associated type so we can create an ItemCtxt. // Using the ItemCtxt convert the HIR for the unresolved assoc type into a // ty which is a fully resolved projection. @@ -143,7 +138,7 @@ 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 tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), "unexpected non-GAT usage of an anon const", ); @@ -160,7 +155,7 @@ 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 tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unable to find type-dependent def for {:?}", parent_node_id), ); @@ -180,12 +175,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (tcx.generics_of(type_dependent_def), idx) } - Node::Ty(&Ty { kind: TyKind::Path(_), .. }) + Node::Ty(&hir::Ty { kind: TyKind::Path(_), .. }) | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. }) | Node::TraitRef(..) | Node::Pat(_) => { let path = match parent_node { - Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. }) + Node::Ty(&hir::Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. }) | Node::TraitRef(&TraitRef { path, .. }) => &*path, Node::Expr(&Expr { kind: @@ -201,14 +196,14 @@ 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 tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unable to find const parent for {} in pat {:?}", hir_id, pat), ); } } _ => { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unexpected const parent path {:?}", parent_node), ); @@ -230,7 +225,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { .position(|ct| ct.hir_id == hir_id) .map(|idx| (idx, seg))) }) else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), "no arg matching AnonConst in path", ); @@ -239,7 +234,7 @@ 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 tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); @@ -249,7 +244,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (generics, arg_index) } - _ => return tcx.ty_error_with_message( + _ => return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unexpected const parent in type_of(): {parent_node:?}"), ), @@ -275,7 +270,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { { tcx.type_of(param_def_id).no_bound_vars().expect("const parameter types cannot be generic") } else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"), ); @@ -311,6 +307,9 @@ fn get_path_containing_arg_in_pat<'hir>( } pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> { + use rustc_hir::*; + use rustc_middle::ty::Ty; + // If we are computing `type_of` the synthesized associated type for an RPITIT in the impl // side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the // associated type in the impl. @@ -323,7 +322,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty return map[&assoc_item.trait_item_def_id.unwrap()]; } Err(_) => { - return ty::EarlyBinder(tcx.ty_error_with_message( + return ty::EarlyBinder::bind(Ty::new_error_with_message( + tcx, DUMMY_SP, "Could not collect return position impl trait in trait tys", )); @@ -331,8 +331,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty } } - use rustc_hir::*; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let icx = ItemCtxt::new(tcx, def_id); @@ -341,13 +339,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty Node::TraitItem(item) => match item.kind { TraitItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } TraitItemKind::Const(ty, body_id) => body_id .and_then(|body_id| { is_suggestable_infer_ty(ty).then(|| { infer_placeholder_type( - tcx, def_id, body_id, ty.span, item.ident, "constant", + tcx, + def_id, + body_id, + ty.span, + item.ident, + "associated constant", ) }) }) @@ -361,11 +364,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty Node::ImplItem(item) => match item.kind { ImplItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } ImplItemKind::Const(ty, body_id) => { if is_suggestable_infer_ty(ty) { - infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant") + infer_placeholder_type( + tcx, + def_id, + body_id, + ty.span, + item.ident, + "associated constant", + ) } else { icx.to_ty(ty) } @@ -411,31 +421,31 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty span: spans.into(), note: (), }); - tcx.ty_error(guar) + Ty::new_error(tcx, guar) } _ => icx.to_ty(*self_ty), }, ItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { let def = tcx.adt_def(def_id); let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_adt(def, substs) + Ty::new_adt(tcx, def, substs) } ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(OpaqueTy { + ItemKind::OpaqueTy(&OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), in_trait, .. }) => { - if in_trait && !tcx.impl_defaultness(owner).has_value() { + if in_trait && !tcx.defaultness(owner).has_value() { span_bug!( tcx.def_span(def_id), "tried to get type of this RPITIT with no definition" @@ -463,10 +473,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty Node::ForeignItem(foreign_item) => match foreign_item.kind { ForeignItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } ForeignItemKind::Static(t, _) => icx.to_ty(t), - ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()), + ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()), }, Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def { @@ -475,7 +485,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty } VariantData::Tuple(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } }, @@ -487,6 +497,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty Node::AnonConst(_) => anon_const_type_of(tcx, def_id), + Node::ConstBlock(_) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + substs.as_inline_const().ty() + } + Node::GenericParam(param) => match ¶m.kind { GenericParamKind::Type { default: Some(ty), .. } | GenericParamKind::Const { ty, .. } => icx.to_ty(ty), @@ -497,7 +512,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty bug!("unexpected sort of node in type_of(): {:?}", x); } }; - ty::EarlyBinder(output) + ty::EarlyBinder::bind(output) } fn infer_placeholder_type<'a>( 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 f7c5b4467..957a6bb34 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -1,3 +1,4 @@ +use rustc_errors::StashKey; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem}; @@ -5,7 +6,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::DUMMY_SP; -use crate::errors::UnconstrainedOpaqueType; +use crate::errors::{TaitForwardCompat, UnconstrainedOpaqueType}; /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions /// laid for "higher-order pattern unification". @@ -59,7 +60,20 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local } } - let Some(hidden) = locator.found else { + if let Some(hidden) = locator.found { + // Only check against typeck if we didn't already error + if !hidden.ty.references_error() { + for concrete_type in locator.typeck_types { + if concrete_type.ty != tcx.erase_regions(hidden.ty) + && !(concrete_type, hidden).references_error() + { + hidden.report_mismatch(&concrete_type, def_id, tcx).emit(); + } + } + } + + hidden.ty + } else { let reported = tcx.sess.emit_err(UnconstrainedOpaqueType { span: tcx.def_span(def_id), name: tcx.item_name(tcx.local_parent(def_id).to_def_id()), @@ -70,21 +84,8 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local _ => "item", }, }); - return tcx.ty_error(reported); - }; - - // Only check against typeck if we didn't already error - if !hidden.ty.references_error() { - for concrete_type in locator.typeck_types { - if concrete_type.ty != tcx.erase_regions(hidden.ty) - && !(concrete_type, hidden).references_error() - { - hidden.report_mismatch(&concrete_type, def_id, tcx).emit(); - } - } + Ty::new_error(tcx, reported) } - - hidden.ty } struct TaitConstraintLocator<'tcx> { @@ -127,16 +128,41 @@ impl TaitConstraintLocator<'_> { // ``` let tables = self.tcx.typeck(item_def_id); if let Some(guar) = tables.tainted_by_errors { - self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) }); + self.found = + Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) }); return; } - let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else { + + let mut constrained = false; + for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types { + if opaque_type_key.def_id != self.def_id { + continue; + } + constrained = true; + if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) { + self.tcx.sess.emit_err(TaitForwardCompat { + span: hidden_type.span, + item_span: self + .tcx + .def_ident_span(item_def_id) + .unwrap_or_else(|| self.tcx.def_span(item_def_id)), + }); + } + let concrete_type = + self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params( + opaque_type_key, + self.tcx, + true, + )); + if self.typeck_types.iter().all(|prev| prev.ty != concrete_type.ty) { + self.typeck_types.push(concrete_type); + } + } + + if !constrained { debug!("no constraints in typeck results"); return; }; - if self.typeck_types.iter().all(|prev| prev.ty != typeck_hidden_ty.ty) { - self.typeck_types.push(typeck_hidden_ty); - } // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types; @@ -146,7 +172,7 @@ impl TaitConstraintLocator<'_> { if let Some(prev) = &mut self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() { let guar = prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit(); - prev.ty = self.tcx.ty_error(guar); + prev.ty = Ty::new_error(self.tcx, guar); } } else { self.found = Some(concrete_type); @@ -190,17 +216,45 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { } } -pub(super) fn find_opaque_ty_constraints_for_rpit( - tcx: TyCtxt<'_>, +pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( + tcx: TyCtxt<'tcx>, def_id: LocalDefId, owner_def_id: LocalDefId, ) -> Ty<'_> { - let concrete = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied(); + let tables = tcx.typeck(owner_def_id); - if let Some(concrete) = concrete { + // Check that all of the opaques we inferred during HIR are compatible. + // FIXME: We explicitly don't check that the types inferred during HIR + // typeck are compatible with the one that we infer during borrowck, + // because that one actually sometimes has consts evaluated eagerly so + // using strict type equality will fail. + let mut hir_opaque_ty: Option<ty::OpaqueHiddenType<'tcx>> = None; + if tables.tainted_by_errors.is_none() { + for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types { + if opaque_type_key.def_id != def_id { + continue; + } + let concrete_type = tcx.erase_regions( + hidden_type.remap_generic_params_to_declaration_params(opaque_type_key, tcx, true), + ); + if let Some(prev) = &mut hir_opaque_ty { + if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() { + prev.report_mismatch(&concrete_type, def_id, tcx).stash( + tcx.def_span(opaque_type_key.def_id), + StashKey::OpaqueHiddenTypeMismatch, + ); + } + } else { + hir_opaque_ty = Some(concrete_type); + } + } + } + + let mir_opaque_ty = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied(); + if let Some(mir_opaque_ty) = mir_opaque_ty { let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id); debug!(?scope); - let mut locator = RpitConstraintChecker { def_id, tcx, found: concrete }; + let mut locator = RpitConstraintChecker { def_id, tcx, found: mir_opaque_ty }; match tcx.hir().get(scope) { Node::Item(it) => intravisit::walk_item(&mut locator, it), @@ -208,27 +262,28 @@ pub(super) fn find_opaque_ty_constraints_for_rpit( Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it), other => bug!("{:?} is not a valid scope for an opaque type item", other), } - } - concrete.map(|concrete| concrete.ty).unwrap_or_else(|| { - let table = tcx.typeck(owner_def_id); - if let Some(guar) = table.tainted_by_errors { - // Some error in the - // owner fn prevented us from populating + mir_opaque_ty.ty + } else { + if let Some(guar) = tables.tainted_by_errors { + // Some error in the owner fn prevented us from populating // the `concrete_opaque_types` table. - tcx.ty_error(guar) + Ty::new_error(tcx, guar) } else { - table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| { + // Fall back to the RPIT we inferred during HIR typeck + if let Some(hir_opaque_ty) = hir_opaque_ty { + hir_opaque_ty.ty + } else { // We failed to resolve the opaque type or it // resolves to itself. We interpret this as the // no values of the hidden type ever being constructed, // so we can just make the hidden type be `!`. // For backwards compatibility reasons, we fall back to // `()` until we the diverging default is changed. - tcx.mk_diverging_default() - }) + Ty::new_diverging_default(tcx) + } } - }) + } } struct RpitConstraintChecker<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 9200c2aec..35882ad35 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -151,7 +151,7 @@ pub fn identify_constrained_generic_params<'tcx>( /// think of any. pub fn setup_constraining_predicates<'tcx>( tcx: TyCtxt<'tcx>, - predicates: &mut [(ty::Predicate<'tcx>, Span)], + predicates: &mut [(ty::Clause<'tcx>, Span)], impl_trait_ref: Option<ty::TraitRef<'tcx>>, input_parameters: &mut FxHashSet<Parameter>, ) { @@ -187,9 +187,7 @@ pub fn setup_constraining_predicates<'tcx>( for j in i..predicates.len() { // Note that we don't have to care about binders here, // as the impl trait ref never contains any late-bound regions. - if let ty::PredicateKind::Clause(ty::Clause::Projection(projection)) = - predicates[j].0.kind().skip_binder() - { + if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() { // Special case: watch out for some kind of sneaky attempt // to project out an associated type defined by this very // trait. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 6e7eb4f6c..c2d2e5f7e 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -5,7 +5,7 @@ use rustc_errors::{ error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -184,6 +184,16 @@ pub struct UnconstrainedOpaqueType { pub what: &'static str, } +#[derive(Diagnostic)] +#[diag(hir_analysis_tait_forward_compat)] +#[note] +pub struct TaitForwardCompat { + #[primary_span] + pub span: Span, + #[note] + pub item_span: Span, +} + pub struct MissingTypeParams { pub span: Span, pub def_span: Span, @@ -857,3 +867,54 @@ pub(crate) enum DropImplPolarity { span: Span, }, } + +#[derive(Diagnostic)] +pub(crate) enum ReturnTypeNotationIllegalParam { + #[diag(hir_analysis_return_type_notation_illegal_param_type)] + Type { + #[primary_span] + span: Span, + #[label] + param_span: Span, + }, + #[diag(hir_analysis_return_type_notation_illegal_param_const)] + Const { + #[primary_span] + span: Span, + #[label] + param_span: Span, + }, +} + +#[derive(Diagnostic)] +pub(crate) enum LateBoundInApit { + #[diag(hir_analysis_late_bound_type_in_apit)] + Type { + #[primary_span] + span: Span, + #[label] + param_span: Span, + }, + #[diag(hir_analysis_late_bound_const_in_apit)] + Const { + #[primary_span] + span: Span, + #[label] + param_span: Span, + }, + #[diag(hir_analysis_late_bound_lifetime_in_apit)] + Lifetime { + #[primary_span] + span: Span, + #[label] + param_span: Span, + }, +} + +#[derive(LintDiagnostic)] +#[diag(hir_analysis_unused_associated_type_bounds)] +#[note] +pub struct UnusedAssociatedTypeBounds { + #[suggestion(code = "")] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index e4c6e6e39..f1765174d 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -79,7 +79,7 @@ fn diagnostic_hir_wf_check<'tcx>( self.tcx, cause, self.param_env, - ty::PredicateKind::WellFormed(tcx_ty.into()), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(tcx_ty.into())), )); for error in ocx.select_all_or_error() { @@ -128,7 +128,9 @@ fn diagnostic_hir_wf_check<'tcx>( ref item => bug!("Unexpected TraitItem {:?}", item), }, hir::Node::Item(item) => match item.kind { - hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty], + hir::ItemKind::TyAlias(ty, _) + | hir::ItemKind::Static(ty, _, _) + | hir::ItemKind::Const(ty, _) => vec![ty], hir::ItemKind::Impl(impl_) => match &impl_.of_trait { Some(t) => t .path diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 612d4ff3d..5526dd4b0 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -106,10 +106,23 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) if item.defaultness(tcx).has_value() { cgp::parameters_for(&tcx.type_of(def_id).subst_identity(), true) } else { - Vec::new() + vec![] } } - ty::AssocKind::Fn | ty::AssocKind::Const => Vec::new(), + ty::AssocKind::Fn => { + if !tcx.lower_impl_trait_in_trait_to_assoc_ty() + && item.defaultness(tcx).has_value() + && tcx.impl_method_has_trait_impl_trait_tys(item.def_id) + && let Ok(table) = tcx.collect_return_position_impl_trait_in_trait_tys(def_id) + { + table.values().copied().flat_map(|ty| { + cgp::parameters_for(&ty.subst_identity(), true) + }).collect() + } else { + vec![] + } + } + ty::AssocKind::Const => vec![], } }) .collect(); 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 e84da2519..c64fb469b 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 @@ -77,7 +77,7 @@ use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt}; @@ -113,7 +113,7 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node let span = tcx.def_span(impl1_def_id); check_has_items(tcx, impl1_def_id, impl2_node, span); - if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) { + if let Ok((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) { let impl2_def_id = impl2_node.def_id(); debug!(?impl2_def_id, ?impl2_substs); @@ -171,16 +171,14 @@ fn get_impl_substs( tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, -) -> Option<(SubstsRef<'_>, SubstsRef<'_>)> { +) -> Result<(SubstsRef<'_>, SubstsRef<'_>), ErrorGuaranteed> { let infcx = &tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(infcx); let param_env = tcx.param_env(impl1_def_id); - - let assumed_wf_types = - ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); + let impl1_span = tcx.def_span(impl1_def_id); + let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?; let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id); - let impl1_span = tcx.def_span(impl1_def_id); let impl2_substs = translate_substs_with_cause( infcx, param_env, @@ -198,8 +196,8 @@ fn get_impl_substs( let errors = ocx.select_all_or_error(); if !errors.is_empty() { - ocx.infcx.err_ctxt().report_fulfillment_errors(&errors); - return None; + let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(&errors); + return Err(guar); } let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types); @@ -207,10 +205,10 @@ fn get_impl_substs( let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { let span = tcx.def_span(impl1_def_id); - tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); - return None; + let guar = tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); + return Err(guar); }; - Some((impl1_substs, impl2_substs)) + Ok((impl1_substs, impl2_substs)) } /// Returns a list of all of the unconstrained subst of the given impl. @@ -235,10 +233,8 @@ fn unconstrained_parent_impl_substs<'tcx>( // what we want here. We want only a list of constrained parameters while // the functions in `cgp` add the constrained parameters to a list of // unconstrained parameters. - for (predicate, _) in impl_generic_predicates.predicates.iter() { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = - predicate.kind().skip_binder() - { + for (clause, _) in impl_generic_predicates.predicates.iter() { + if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder() { let projection_ty = proj.projection_ty; let projected_ty = proj.term; @@ -340,8 +336,11 @@ fn check_predicates<'tcx>( impl2_substs: SubstsRef<'tcx>, span: Span, ) { - let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs); - let impl1_predicates: Vec<_> = traits::elaborate(tcx, instantiated.into_iter()).collect(); + let impl1_predicates: Vec<_> = traits::elaborate( + tcx, + tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).into_iter(), + ) + .collect(); let mut impl2_predicates = if impl2_node.is_from_trait() { // Always applicable traits have to be always applicable without any @@ -352,8 +351,8 @@ fn check_predicates<'tcx>( tcx, tcx.predicates_of(impl2_node.def_id()) .instantiate(tcx, impl2_substs) - .predicates - .into_iter(), + .into_iter() + .map(|(c, _s)| c.as_predicate()), ) .collect() }; @@ -377,13 +376,13 @@ fn check_predicates<'tcx>( let always_applicable_traits = impl1_predicates .iter() .copied() - .filter(|&(predicate, _)| { + .filter(|(clause, _span)| { matches!( - trait_predicate_kind(tcx, predicate), + trait_predicate_kind(tcx, clause.as_predicate()), Some(TraitSpecializationKind::AlwaysApplicable) ) }) - .map(|(pred, _span)| pred); + .map(|(c, _span)| c.as_predicate()); // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs { @@ -398,9 +397,12 @@ fn check_predicates<'tcx>( } impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits)); - for (predicate, span) in impl1_predicates { - if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) { - check_specialization_on(tcx, predicate, span) + for (clause, span) in impl1_predicates { + if !impl2_predicates + .iter() + .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span)) + { + check_specialization_on(tcx, clause.as_predicate(), span) } } } @@ -438,8 +440,8 @@ fn trait_predicates_eq<'tcx>( let pred2_kind = predicate2.kind().skip_binder(); let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) { ( - ty::PredicateKind::Clause(ty::Clause::Trait(pred1)), - ty::PredicateKind::Clause(ty::Clause::Trait(pred2)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred1)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred2)), ) => (pred1, pred2), // Just use plain syntactic equivalence if either of the predicates aren't // trait predicates or have bound vars. @@ -478,7 +480,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc _ if predicate.is_global() => (), // We allow specializing on explicitly marked traits with no associated // items. - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _, @@ -498,7 +500,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc .emit(); } } - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term, })) => { @@ -509,7 +511,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc ) .emit(); } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => { + ty::PredicateKind::Clause(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 @@ -532,24 +534,23 @@ fn trait_predicate_kind<'tcx>( predicate: ty::Predicate<'tcx>, ) -> Option<TraitSpecializationKind> { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _, })) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::Projection(_)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + 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::WellFormed(_) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, + | ty::PredicateKind::Ambiguous => None, } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 5cd2cd50c..a68832d96 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,8 +59,6 @@ This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(box_patterns)] #![feature(control_flow_enum)] -#![feature(drain_filter)] -#![feature(hash_drain_filter)] #![feature(if_let_guard)] #![feature(is_sorted)] #![feature(iter_intersperse)] @@ -321,16 +319,19 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { expected_return_type = main_fnsig.output(); } else { // standard () main return type - expected_return_type = ty::Binder::dummy(tcx.mk_unit()); + expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx)); } if error { return; } - let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| { - tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust) - })); + let se_ty = Ty::new_fn_ptr( + tcx, + expected_return_type.map_bound(|expected_return_type| { + tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust) + }), + ); require_same_types( tcx, @@ -341,7 +342,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { ), param_env, se_ty, - tcx.mk_fn_ptr(main_fnsig), + Ty::new_fn_ptr(tcx, main_fnsig), ); } fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { @@ -399,13 +400,16 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { } } - let se_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( - [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))], - tcx.types.isize, - false, - hir::Unsafety::Normal, - Abi::Rust, - ))); + let se_ty = Ty::new_fn_ptr( + tcx, + ty::Binder::dummy(tcx.mk_fn_sig( + [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))], + tcx.types.isize, + false, + hir::Unsafety::Normal, + Abi::Rust, + )), + ); require_same_types( tcx, @@ -416,7 +420,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { ), ty::ParamEnv::empty(), // start should not have any where bounds. se_ty, - tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()), + Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).subst_identity()), ); } _ => { diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 357deb07b..a7fca41f8 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -30,45 +30,34 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { // process predicates and convert to `RequiredPredicates` entry, see below for &(predicate, span) in predicates.predicates { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(OutlivesPredicate( - ty, - reg, - ))) => insert_outlives_predicate( - tcx, - ty.into(), - reg, - span, - &mut required_predicates, - ), - - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(OutlivesPredicate( - reg1, - reg2, - ))) => insert_outlives_predicate( - tcx, - reg1.into(), - reg2, - span, - &mut required_predicates, - ), - - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::WellFormed(..) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::TypeWellFormedFromEnv(..) => (), + ty::ClauseKind::TypeOutlives(OutlivesPredicate(ty, reg)) => { + insert_outlives_predicate( + tcx, + ty.into(), + reg, + span, + &mut required_predicates, + ) + } + + ty::ClauseKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => { + insert_outlives_predicate( + tcx, + reg1.into(), + reg2, + span, + &mut required_predicates, + ) + } + ty::ClauseKind::Trait(_) + | ty::ClauseKind::Projection(_) + | ty::ClauseKind::ConstArgHasType(_, _) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => {} } } - ty::EarlyBinder(required_predicates) + ty::EarlyBinder::bind(required_predicates) }) } } diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index 0cd2fc1aa..71dca918f 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -68,12 +68,13 @@ pub(super) fn infer_predicates( // Therefore mark `predicates_added` as true and which will ensure // we walk the crates again and re-calculate predicates for all // items. - let item_predicates_len: usize = - global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.0.len()); + let item_predicates_len: usize = global_inferred_outlives + .get(&item_did.to_def_id()) + .map_or(0, |p| p.as_ref().skip_binder().len()); if item_required_predicates.len() > item_predicates_len { predicates_added = true; global_inferred_outlives - .insert(item_did.to_def_id(), ty::EarlyBinder(item_required_predicates)); + .insert(item_did.to_def_id(), ty::EarlyBinder::bind(item_required_predicates)); } } @@ -137,7 +138,9 @@ fn insert_required_predicates_to_be_wf<'tcx>( // 'a` holds for `Foo`. debug!("Adt"); if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) { - for (unsubstituted_predicate, &span) in &unsubstituted_predicates.0 { + for (unsubstituted_predicate, &span) in + unsubstituted_predicates.as_ref().skip_binder() + { // `unsubstituted_predicate` is `U: 'b` in the // example above. So apply the substitution to // get `T: 'a` (or `predicate`): @@ -251,7 +254,7 @@ fn check_explicit_predicates<'tcx>( ); let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id); - for (outlives_predicate, &span) in &explicit_predicates.0 { + for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() { debug!("outlives_predicate = {:?}", &outlives_predicate); // Careful: If we are inferring the effects of a `dyn Trait<..>` diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index a8596c707..48624cefe 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_middle::query::Providers; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; +use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -20,7 +20,8 @@ pub fn provide(providers: &mut Providers) { fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] { let id = tcx.hir().local_def_id_to_hir_id(item_def_id); - if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() + if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) + && tcx.features().generic_const_exprs { if tcx.hir().opt_const_param_default_param_def_id(id).is_some() { // In `generics_of` we set the generics' parent to be our parent's parent which means that @@ -51,9 +52,9 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec<String> = predicates .iter() - .map(|(out_pred, _)| match out_pred { - ty::Clause::RegionOutlives(p) => p.to_string(), - ty::Clause::TypeOutlives(p) => p.to_string(), + .map(|(out_pred, _)| match out_pred.kind().skip_binder() { + ty::ClauseKind::RegionOutlives(p) => p.to_string(), + ty::ClauseKind::TypeOutlives(p) => p.to_string(), err => bug!("unexpected clause {:?}", err), }) .collect(); @@ -98,24 +99,29 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { let predicates = global_inferred_outlives .iter() .map(|(&def_id, set)| { - let predicates = &*tcx.arena.alloc_from_iter(set.0.iter().filter_map( - |(ty::OutlivesPredicate(kind1, region2), &span)| { - match kind1.unpack() { - GenericArgKind::Type(ty1) => Some(( - ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)), - span, - )), - GenericArgKind::Lifetime(region1) => Some(( - ty::Clause::RegionOutlives(ty::OutlivesPredicate(region1, *region2)), - span, - )), - GenericArgKind::Const(_) => { - // Generic consts don't impose any constraints. - None + let predicates = + &*tcx.arena.alloc_from_iter(set.as_ref().skip_binder().iter().filter_map( + |(ty::OutlivesPredicate(kind1, region2), &span)| { + match kind1.unpack() { + GenericArgKind::Type(ty1) => Some(( + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)) + .to_predicate(tcx), + span, + )), + GenericArgKind::Lifetime(region1) => Some(( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( + region1, *region2, + )) + .to_predicate(tcx), + span, + )), + GenericArgKind::Const(_) => { + // Generic consts don't impose any constraints. + None + } } - } - }, - )); + }, + )); (def_id, predicates) }) .collect(); diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 3ebd9e134..066e74491 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -51,20 +51,19 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { | DefKind::Struct | DefKind::Union | DefKind::Variant - | DefKind::Ctor(..) => {} + | DefKind::Ctor(..) => { + // These are inferred. + let crate_map = tcx.crate_variances(()); + return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); + } DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => { return variance_of_opaque(tcx, item_def_id); } - _ => { - // Variance not relevant. - span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item") - } + _ => {} } - // Everything else must be inferred. - - let crate_map = tcx.crate_variances(()); - crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]) + // Variance not relevant. + span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item"); } #[instrument(level = "trace", skip(tcx), ret)] @@ -119,7 +118,8 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) check whether this is necessary // at all for RPITITs. ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if self.tcx.is_impl_trait_in_trait(*def_id) => + if self.tcx.is_impl_trait_in_trait(*def_id) + && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() => { self.visit_opaque(*def_id, substs) } @@ -162,28 +162,25 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // which thus mentions `'a` and should thus accept hidden types that borrow 'a // instead of requiring an additional `+ 'a`. match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: ty::TraitRef { def_id: _, substs, .. }, constness: _, polarity: _, - })) => { + }) => { for subst in &substs[1..] { subst.visit_with(&mut collector); } } - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty: ty::AliasTy { substs, .. }, term, - })) => { + }) => { for subst in &substs[1..] { subst.visit_with(&mut collector); } term.visit_with(&mut collector); } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - _, - region, - ))) => { + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_, region)) => { region.visit_with(&mut collector); } _ => { |