From 9835e2ae736235810b4ea1c162ca5e65c547e770 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 04:49:50 +0200 Subject: Merging upstream version 1.71.1+dfsg1. Signed-off-by: Daniel Baumann --- .../rustc_hir_analysis/src/coherence/builtin.rs | 287 ++++++++++++--------- 1 file changed, 165 insertions(+), 122 deletions(-) (limited to 'compiler/rustc_hir_analysis/src/coherence/builtin.rs') diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 0f40cca94..a98d8e171 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -1,9 +1,11 @@ //! Check properties that are required by built-in traits and set //! up data structures required by type-checking/codegen. -use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem}; +use crate::errors::{ + ConstParamTyImplOnNonAdt, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem, +}; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, MultiSpan}; +use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -14,9 +16,11 @@ use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::misc::{ - type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason, + type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy, + ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason, }; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCause}; @@ -27,6 +31,7 @@ pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) { Checker { tcx, trait_def_id } .check(lang_items.drop_trait(), visit_implementation_of_drop) .check(lang_items.copy_trait(), visit_implementation_of_copy) + .check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty) .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized) .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn); } @@ -74,120 +79,16 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); - let span = match tcx.hir().expect_item(impl_did).kind { - ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. }) => return, - ItemKind::Impl(impl_) => impl_.self_ty.span, - _ => bug!("expected Copy impl item"), + let span = match tcx.hir().expect_item(impl_did).expect_impl() { + hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return, + hir::Impl { self_ty, .. } => self_ty.span, }; let cause = traits::ObligationCause::misc(span, impl_did); match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) { Ok(()) => {} - Err(CopyImplementationError::InfrigingFields(fields)) => { - let mut err = struct_span_err!( - tcx.sess, - span, - E0204, - "the trait `Copy` cannot be implemented for this type" - ); - - // We'll try to suggest constraining type parameters to fulfill the requirements of - // their `Copy` implementation. - let mut errors: BTreeMap<_, Vec<_>> = Default::default(); - let mut bounds = vec![]; - - let mut seen_tys = FxHashSet::default(); - - for (field, ty, reason) in fields { - // Only report an error once per type. - if !seen_tys.insert(ty) { - continue; - } - - let field_span = tcx.def_span(field.did); - err.span_label(field_span, "this field does not implement `Copy`"); - - match reason { - InfringingFieldsReason::Fulfill(fulfillment_errors) => { - for error in fulfillment_errors { - let error_predicate = error.obligation.predicate; - // Only note if it's not the root obligation, otherwise it's trivial and - // should be self-explanatory (i.e. a field literally doesn't implement Copy). - - // FIXME: This error could be more descriptive, especially if the error_predicate - // contains a foreign type or if it's a deeply nested type... - if error_predicate != error.root_obligation.predicate { - errors - .entry((ty.to_string(), error_predicate.to_string())) - .or_default() - .push(error.obligation.cause.span); - } - if let ty::PredicateKind::Clause(ty::Clause::Trait( - ty::TraitPredicate { - trait_ref, - polarity: ty::ImplPolarity::Positive, - .. - }, - )) = error_predicate.kind().skip_binder() - { - let ty = trait_ref.self_ty(); - if let ty::Param(_) = ty.kind() { - bounds.push(( - format!("{ty}"), - trait_ref.print_only_trait_path().to_string(), - Some(trait_ref.def_id), - )); - } - } - } - } - InfringingFieldsReason::Regions(region_errors) => { - for error in region_errors { - let ty = ty.to_string(); - match error { - RegionResolutionError::ConcreteFailure(origin, a, b) => { - let predicate = format!("{b}: {a}"); - errors - .entry((ty.clone(), predicate.clone())) - .or_default() - .push(origin.span()); - if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() { - bounds.push((b.to_string(), a.to_string(), None)); - } - } - RegionResolutionError::GenericBoundFailure(origin, a, b) => { - let predicate = format!("{a}: {b}"); - errors - .entry((ty.clone(), predicate.clone())) - .or_default() - .push(origin.span()); - if let infer::region_constraints::GenericKind::Param(_) = a { - bounds.push((a.to_string(), b.to_string(), None)); - } - } - _ => continue, - } - } - } - } - } - for ((ty, error_predicate), spans) in errors { - let span: MultiSpan = spans.into(); - err.span_note( - span, - &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate), - ); - } - suggest_constraining_type_params( - tcx, - tcx.hir().get_generics(impl_did).expect("impls always have generics"), - &mut err, - bounds.iter().map(|(param, constraint, def_id)| { - (param.as_str(), constraint.as_str(), *def_id) - }), - None, - ); - err.emit(); + Err(CopyImplementationError::InfringingFields(fields)) => { + infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span); } Err(CopyImplementationError::NotAnAdt) => { tcx.sess.emit_err(CopyImplOnNonAdt { span }); @@ -198,6 +99,29 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { } } +fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) { + let self_type = tcx.type_of(impl_did).subst_identity(); + assert!(!self_type.has_escaping_bound_vars()); + + let param_env = tcx.param_env(impl_did); + + let span = match tcx.hir().expect_item(impl_did).expect_impl() { + hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return, + impl_ => impl_.self_ty.span, + }; + + let cause = traits::ObligationCause::misc(span, impl_did); + match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) { + Ok(()) => {} + Err(ConstParamTyImplementationError::InfrigingFields(fields)) => { + infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span); + } + Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => { + tcx.sess.emit_err(ConstParamTyImplOnNonAdt { span }); + } + } +} + fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) { debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did); @@ -289,7 +213,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef for structs containing the field being coerced, \ ZST fields with 1 byte alignment, and nothing else", ) - .note(&format!( + .note(format!( "extra field `{}` of type `{}` is not allowed", field.name, ty_a, )) @@ -317,7 +241,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef for a coercion between structures with a single field \ being coerced", ) - .note(&format!( + .note(format!( "currently, {} fields need coercions: {}", coerced_fields.len(), coerced_fields @@ -341,10 +265,11 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef tcx, cause.clone(), param_env, - ty::Binder::dummy(tcx.mk_trait_ref( + ty::TraitRef::new( + tcx, dispatch_from_dyn_trait, [field.ty(tcx, substs_a), field.ty(tcx, substs_b)], - )), + ), )); } let errors = ocx.select_all_or_error(); @@ -373,9 +298,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); - let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| { - tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err.to_string())); - }); + let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span)); let source = tcx.type_of(impl_did).subst_identity(); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity(); @@ -545,7 +468,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe "`CoerceUnsized` may only be implemented for \ a coercion between structures with one field being coerced", ) - .note(&format!( + .note(format!( "currently, {} fields need coercions: {}", diff_fields.len(), diff_fields @@ -580,8 +503,12 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe // Register an obligation for `A: Trait`. let ocx = ObligationCtxt::new(&infcx); let cause = traits::ObligationCause::misc(span, impl_did); - let obligation = - Obligation::new(tcx, cause, param_env, tcx.mk_trait_ref(trait_def_id, [source, target])); + let obligation = Obligation::new( + tcx, + cause, + param_env, + ty::TraitRef::new(tcx, trait_def_id, [source, target]), + ); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); if !errors.is_empty() { @@ -594,3 +521,119 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe CoerceUnsizedInfo { custom_kind: kind } } + +fn infringing_fields_error( + tcx: TyCtxt<'_>, + fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>, + lang_item: LangItem, + impl_did: LocalDefId, + impl_span: Span, +) -> ErrorGuaranteed { + let trait_did = tcx.require_lang_item(lang_item, Some(impl_span)); + + let trait_name = tcx.def_path_str(trait_did); + + let mut err = struct_span_err!( + tcx.sess, + impl_span, + E0204, + "the trait `{trait_name}` cannot be implemented for this type" + ); + + // We'll try to suggest constraining type parameters to fulfill the requirements of + // their `Copy` implementation. + let mut errors: BTreeMap<_, Vec<_>> = Default::default(); + let mut bounds = vec![]; + + let mut seen_tys = FxHashSet::default(); + + for (field, ty, reason) in fields { + // Only report an error once per type. + if !seen_tys.insert(ty) { + continue; + } + + let field_span = tcx.def_span(field.did); + err.span_label(field_span, format!("this field does not implement `{trait_name}`")); + + match reason { + InfringingFieldsReason::Fulfill(fulfillment_errors) => { + for error in fulfillment_errors { + let error_predicate = error.obligation.predicate; + // Only note if it's not the root obligation, otherwise it's trivial and + // should be self-explanatory (i.e. a field literally doesn't implement Copy). + + // FIXME: This error could be more descriptive, especially if the error_predicate + // contains a foreign type or if it's a deeply nested type... + if error_predicate != error.root_obligation.predicate { + errors + .entry((ty.to_string(), error_predicate.to_string())) + .or_default() + .push(error.obligation.cause.span); + } + if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + trait_ref, + polarity: ty::ImplPolarity::Positive, + .. + })) = error_predicate.kind().skip_binder() + { + let ty = trait_ref.self_ty(); + if let ty::Param(_) = ty.kind() { + bounds.push(( + format!("{ty}"), + trait_ref.print_only_trait_path().to_string(), + Some(trait_ref.def_id), + )); + } + } + } + } + InfringingFieldsReason::Regions(region_errors) => { + for error in region_errors { + let ty = ty.to_string(); + match error { + RegionResolutionError::ConcreteFailure(origin, a, b) => { + let predicate = format!("{b}: {a}"); + errors + .entry((ty.clone(), predicate.clone())) + .or_default() + .push(origin.span()); + if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() { + bounds.push((b.to_string(), a.to_string(), None)); + } + } + RegionResolutionError::GenericBoundFailure(origin, a, b) => { + let predicate = format!("{a}: {b}"); + errors + .entry((ty.clone(), predicate.clone())) + .or_default() + .push(origin.span()); + if let infer::region_constraints::GenericKind::Param(_) = a { + bounds.push((a.to_string(), b.to_string(), None)); + } + } + _ => continue, + } + } + } + } + } + for ((ty, error_predicate), spans) in errors { + let span: MultiSpan = spans.into(); + err.span_note( + span, + format!("the `{trait_name}` impl for `{ty}` requires that `{error_predicate}`"), + ); + } + suggest_constraining_type_params( + tcx, + tcx.hir().get_generics(impl_did).expect("impls always have generics"), + &mut err, + bounds + .iter() + .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)), + None, + ); + + err.emit() +} -- cgit v1.2.3