From eb366609130be41640bd47772cf37bc18f5b25db Mon Sep 17 00:00:00 2001 From: sjwang05 <63834813+sjwang05@users.noreply.github.com> Date: Thu, 25 Jan 2024 19:18:13 -0800 Subject: [PATCH] Fix inner ty check --- compiler/rustc_hir_analysis/messages.ftl | 8 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 47 ++-- .../src/coherence/builtin.rs | 29 ++- compiler/rustc_hir_analysis/src/errors.rs | 26 +- .../rustc_trait_selection/src/traits/misc.rs | 222 +++++++++++------- .../const_param_ty_bad_regions.rs | 16 ++ .../const_param_ty_bad_regions.stderr | 22 ++ .../const_param_ty_good_with_bounds.rs | 21 ++ .../const_param_ty_impl_bad_inner_ty.rs | 2 +- .../const_param_ty_impl_bad_inner_ty.stderr | 25 +- 10 files changed, 268 insertions(+), 150 deletions(-) create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_bad_regions.rs create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_bad_regions.stderr create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_good_with_bounds.rs diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index c78a81e75f0c8..409d08660417e 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -80,12 +80,14 @@ hir_analysis_const_impl_for_non_const_trait = hir_analysis_const_param_ty_impl_on_infringing_inner_ty = the trait `ConstParamTy` cannot be implemented for this type - .label = this {$def_descr} does not implement `ConstParamTy` - .suggestion = consider annotating this {$def_descr} with `#[derive(ConstParamTy)]` + .label = this type does not implement `ConstParamTy` + +hir_analysis_const_param_ty_impl_on_infringing_inner_ty_sugg = + consider annotating with `#[derive(ConstParamTy)]` hir_analysis_const_param_ty_impl_on_non_adt = the trait `ConstParamTy` may not be implemented for this type - .label = type is not a structure or enumeration + .label = the type `{$ty}` is not a structure or enumeration hir_analysis_const_specialize = cannot specialize on const impl with non-const impl diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 02c61dd5457f9..a0ebcf9260125 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -939,6 +939,22 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), Ok(()) }) } else { + fn ty_is_local(ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Adt(adt_def, ..) => adt_def.did().is_local(), + // Arrays and slices use the inner type's `ConstParamTy`. + ty::Array(ty, ..) => ty_is_local(*ty), + ty::Slice(ty) => ty_is_local(*ty), + // `&` references use the inner type's `ConstParamTy`. + // `&mut` are not supported. + ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty), + // Say that a tuple is local if any of its components are local. + // This is not strictly correct, but it's likely that the user can fix the local component. + ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)), + _ => false, + } + } + let mut diag = match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => return Ok(()), ty::FnPtr(_) => tcx.dcx().struct_span_err( @@ -962,35 +978,16 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), tcx, tcx.param_env(param.def_id), ty, - cause, + &cause, ) { // Can never implement `ConstParamTy`, don't suggest anything. - Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false, + Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed(..)) => false, // May be able to implement `ConstParamTy`. Only emit the feature help // if the type is local, since the user may be able to fix the local type. - Err(ConstParamTyImplementationError::InfrigingFields(..)) => { - fn ty_is_local(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Adt(adt_def, ..) => adt_def.did().is_local(), - // Arrays and slices use the inner type's `ConstParamTy`. - ty::Array(ty, ..) => ty_is_local(*ty), - ty::Slice(ty) => ty_is_local(*ty), - // `&` references use the inner type's `ConstParamTy`. - // `&mut` are not supported. - ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty), - // Say that a tuple is local if any of its components are local. - // This is not strictly correct, but it's likely that the user can fix the local component. - ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)), - _ => false, - } - } - - ty_is_local(ty) - } - // Same as above. - Err(ConstParamTyImplementationError::InfringingInnerTy(def_id)) => { - def_id.is_local() - } + Err( + ConstParamTyImplementationError::InfrigingFields(..) + | ConstParamTyImplementationError::InfringingInnerTy(..), + ) => ty_is_local(ty), // Implments `ConstParamTy`, suggest adding the feature to enable. Ok(..) => true, }; diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index eb95c1ace0f30..6c502bf7b88c8 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -127,22 +127,31 @@ fn visit_implementation_of_const_param_ty( }; let cause = traits::ObligationCause::misc(span, impl_did); - match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) { + match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, &cause) { Ok(()) => Ok(()), Err(ConstParamTyImplementationError::InfrigingFields(fields)) => { Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span)) } - Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => { - Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span })) + Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed(ty)) => { + Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span, ty })) } - Err(ConstParamTyImplementationError::InfringingInnerTy(def_id)) => { - let def_span = tcx.def_span(def_id); - tcx.dcx().emit_err(errors::ConstParamTyImplOnInfringingInnerTy { + Err(ConstParamTyImplementationError::InfringingInnerTy(def_ids)) => { + let mut def_spans = vec![]; + let mut suggs = vec![]; + for def_id in def_ids { + let def_span = tcx.def_span(def_id); + def_spans.push(def_span); + if def_id.is_local() { + suggs.push(errors::ConstParamTyImplOnInfringingInnerTySugg { + span: def_span.shrink_to_lo(), + }); + } + } + Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnInfringingInnerTy { span, - def_span, - def_descr: tcx.def_descr(def_id), - sugg: def_id.is_local().then_some(def_span.shrink_to_lo()), - }); + def_spans, + suggs, + })) } } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9a9d3d7405cda..448852750cb60 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -221,10 +221,11 @@ pub struct CopyImplOnNonAdt { #[derive(Diagnostic)] #[diag(hir_analysis_const_param_ty_impl_on_non_adt)] -pub struct ConstParamTyImplOnNonAdt { +pub struct ConstParamTyImplOnNonAdt<'tcx> { #[primary_span] #[label] pub span: Span, + pub ty: Ty<'tcx>, } #[derive(Diagnostic)] @@ -233,14 +234,21 @@ pub struct ConstParamTyImplOnInfringingInnerTy { #[primary_span] pub span: Span, #[label] - pub def_span: Span, - pub def_descr: &'static str, - #[suggestion( - applicability = "maybe-incorrect", - style = "verbose", - code = "#[derive(ConstParamTy)]\n" - )] - pub sugg: Option, + pub def_spans: Vec, + #[subdiagnostic] + pub suggs: Vec, +} + +#[derive(Subdiagnostic)] +#[suggestion( + hir_analysis_const_param_ty_impl_on_infringing_inner_ty_sugg, + applicability = "maybe-incorrect", + style = "verbose", + code = "#[derive(ConstParamTy)]\n" +)] +pub struct ConstParamTyImplOnInfringingInnerTySugg { + #[primary_span] + pub span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 42f2152840f7b..cf152d24ea83b 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -11,6 +11,7 @@ use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; use rustc_middle::ty::{self, AdtDef, GenericArg, List, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; use rustc_span::DUMMY_SP; use super::outlives_bounds::InferCtxtExt; @@ -23,8 +24,8 @@ pub enum CopyImplementationError<'tcx> { pub enum ConstParamTyImplementationError<'tcx> { InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), - InfringingInnerTy(DefId), - NotAnAdtOrBuiltinAllowed, + InfringingInnerTy(Vec), + NotAnAdtOrBuiltinAllowed(Ty<'tcx>), } pub enum InfringingFieldsReason<'tcx> { @@ -69,7 +70,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( self_type, adt, args, - parent_cause, + &parent_cause, hir::LangItem::Copy, ) .map_err(CopyImplementationError::InfringingFields)?; @@ -91,62 +92,82 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, - parent_cause: ObligationCause<'tcx>, + parent_cause: &ObligationCause<'tcx>, ) -> Result<(), ConstParamTyImplementationError<'tcx>> { - // Special case for impls like `impl ConstParamTy for &Foo`, where - // Foo doesn't `impl ConstParamTy`. These kinds of impls aren't caught - // by coherence checking since `core`'s impl is restricted to T: ConstParamTy. - // `has_concrete_skeleton()` avoids reporting `core`'s blanket impl. - let check_inner_ty = |ty: Ty<'tcx>, cause| { - let ty = ty.peel_refs(); - if ty.has_concrete_skeleton() { - type_allowed_to_implement_const_param_ty(tcx, param_env, ty, cause)?; - // Check the inner tys in refs, tuples, arrays, or slices implement `ConstParamTy`. - // This additional logic is needed because we need to check not only if all fields - // of the type implement ConstParamTy, but also that the type itself implements - // ConstParamTy. Simply recursing into the inner type only checks the former. - // `type_allowed_to_implement_const_param_ty` takes care of other non-ADT types - // for us. - if let &ty::Adt(adt, _) = ty.kind() { - let adt_did = adt.did(); - let adt_span = tcx.def_span(adt_did); - let trait_did = tcx.require_lang_item(hir::LangItem::ConstParamTy, Some(adt_span)); + // impls like `impl ConstParamTy for &Foo` where Foo doesn't `impl ConstParamTy` + // need special-casing. These kinds of impls aren't caught by coherence checking + // since `core`'s impl is restricted to T: ConstParamTy. + // Additionally, we need to check that the inner tys in refs, tuples, arrays, + // or slices implement `ConstParamTy`. Simply recursing into the inner type only + // checks if all fields of the type implement ConstParamTy. We only do this for + // ADTs because recursing with `type_allowed_to_implement_const_param_ty` takes + // care of other non-ADT types for us. + // `has_concrete_skeletion` avoids reporting `core`'s blanket impls. - let infcx = tcx.infer_ctxt().build(); - let ocx = traits::ObligationCtxt::new(&infcx); + let (adt, args) = match self_type.kind() { + // `core` provides these impls, but only where the inner type is `ConstParamTy`, + // so we need to check and deny impls where the inner type is not `ConstParamTy` + &ty::Ref(.., ty, hir::Mutability::Not) | &ty::Array(ty, ..) | &ty::Slice(ty) => { + let ty = ty.peel_refs(); + if !ty.has_concrete_skeleton() { + return Ok(()); + } + type_allowed_to_implement_const_param_ty(tcx, param_env, ty, parent_cause)?; - let ty = ocx.normalize(&ObligationCause::dummy_with_span(adt_span), param_env, ty); - let norm_errs = ocx.select_where_possible(); - if !norm_errs.is_empty() || ty.references_error() { - return Ok(()); - } + if let ty::Adt(adt, _) = ty.kind() { + let adt_did = adt.did(); + let adt_span = tcx.def_span(adt_did); - ocx.register_bound( - ObligationCause::dummy_with_span(adt_span), + let errs = field_implements_trait( + tcx, param_env, + self_type, ty, - trait_did, + adt_span, + ObligationCause::dummy_with_span(adt_span), + parent_cause, + hir::LangItem::ConstParamTy, ); - let errs = ocx.select_all_or_error(); if !errs.is_empty() { - return Err(ConstParamTyImplementationError::InfringingInnerTy(adt_did)); + return Err(ConstParamTyImplementationError::InfringingInnerTy(vec![adt_did])); } } - } - - Ok(()) - }; - let (adt, args) = match self_type.kind() { - // `core` provides these impls, but only where the inner type is `ConstParamTy`, - // so we need to check and deny impls where the inner type is not `ConstParamTy` - &ty::Ref(.., ty, hir::Mutability::Not) | &ty::Array(ty, ..) | &ty::Slice(ty) => { - return check_inner_ty(ty, parent_cause); + return Ok(()); } &ty::Tuple(tys) => { + let mut all_errs = Vec::new(); + let mut adt_dids = Vec::new(); + for ty in tys { - check_inner_ty(ty, parent_cause.clone())?; + let ty = ty.peel_refs(); + if !ty.has_concrete_skeleton() { + return Ok(()); + } + type_allowed_to_implement_const_param_ty(tcx, param_env, ty, parent_cause)?; + + if let ty::Adt(adt, _) = ty.kind() { + let adt_did = adt.did(); + let adt_span = tcx.def_span(adt_did); + let errs = field_implements_trait( + tcx, + param_env, + self_type, + ty, + adt_span, + ObligationCause::dummy_with_span(adt_span), + parent_cause, + hir::LangItem::ConstParamTy, + ); + if !errs.is_empty() { + all_errs.extend(errs); + adt_dids.push(adt_did); + } + } + } + if !all_errs.is_empty() { + return Err(ConstParamTyImplementationError::InfringingInnerTy(adt_dids)); } return Ok(()); } @@ -156,7 +177,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( &ty::Adt(adt, args) => (adt, args), - _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed), + _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed(self_type)), }; all_fields_implement_trait( @@ -180,18 +201,12 @@ pub fn all_fields_implement_trait<'tcx>( self_type: Ty<'tcx>, adt: AdtDef<'tcx>, args: &'tcx List>, - parent_cause: ObligationCause<'tcx>, + parent_cause: &ObligationCause<'tcx>, lang_item: LangItem, ) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> { - let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span)); - let mut infringing = Vec::new(); for variant in adt.variants() { for field in &variant.fields { - // Do this per-field to get better error messages. - let infcx = tcx.infer_ctxt().build(); - let ocx = traits::ObligationCtxt::new(&infcx); - let unnormalized_ty = field.ty(tcx, args); if unnormalized_ty.references_error() { continue; @@ -216,48 +231,85 @@ pub fn all_fields_implement_trait<'tcx>( } else { ObligationCause::dummy_with_span(field_ty_span) }; - let ty = ocx.normalize(&normalization_cause, param_env, unnormalized_ty); - let normalization_errors = ocx.select_where_possible(); - - // NOTE: The post-normalization type may also reference errors, - // such as when we project to a missing type or we have a mismatch - // between expected and found const-generic types. Don't report an - // additional copy error here, since it's not typically useful. - if !normalization_errors.is_empty() || ty.references_error() { - tcx.dcx().span_delayed_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id))); - continue; - } - - ocx.register_bound( - ObligationCause::dummy_with_span(field_ty_span), - param_env, - ty, - trait_def_id, - ); - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors))); - } - // Check regions assuming the self type of the impl is WF - let outlives_env = OutlivesEnvironment::with_bounds( - param_env, - infcx.implied_bounds_tys( + infringing.extend( + field_implements_trait( + tcx, param_env, - parent_cause.body_id, - &FxIndexSet::from_iter([self_type]), - ), + self_type, + unnormalized_ty, + field_ty_span, + normalization_cause, + parent_cause, + lang_item, + ) + .into_iter() + .map(|(ty, reason)| (field, ty, reason)), ); - let errors = infcx.resolve_regions(&outlives_env); - if !errors.is_empty() { - infringing.push((field, ty, InfringingFieldsReason::Regions(errors))); - } } } if infringing.is_empty() { Ok(()) } else { Err(infringing) } } +fn field_implements_trait<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + self_type: Ty<'tcx>, + unnormalized_ty: Ty<'tcx>, + span: Span, + normalization_cause: ObligationCause<'tcx>, + parent_cause: &ObligationCause<'tcx>, + lang_item: LangItem, +) -> Vec<(Ty<'tcx>, InfringingFieldsReason<'tcx>)> { + let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span)); + + let infcx = tcx.infer_ctxt().build(); + let ocx = traits::ObligationCtxt::new(&infcx); + + let ty = ocx.normalize(&normalization_cause, param_env, unnormalized_ty); + let normalization_errors = ocx.select_where_possible(); + + // NOTE: The post-normalization type may also reference errors, + // such as when we project to a missing type or we have a mismatch + // between expected and found const-generic types. Don't report an + // additional copy error here, since it's not typically useful. + if !normalization_errors.is_empty() || ty.references_error() { + tcx.dcx().span_delayed_bug( + span, + format!( + "couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", + tr = tcx.def_path_str(trait_def_id) + ), + ); + return Vec::new(); + } + + let mut infringing = Vec::new(); + + ocx.register_bound(ObligationCause::dummy_with_span(span), param_env, ty, trait_def_id); + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infringing.push((ty, InfringingFieldsReason::Fulfill(errors))); + } + + // Check regions assuming the self type of the impl is WF + let outlives_env = OutlivesEnvironment::with_bounds( + param_env, + infcx.implied_bounds_tys( + param_env, + parent_cause.body_id, + &FxIndexSet::from_iter([self_type]), + ), + ); + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + infringing.push((ty, InfringingFieldsReason::Regions(errors))); + } + + infringing +} + pub fn check_tys_might_be_eq<'tcx>( tcx: TyCtxt<'tcx>, canonical: Canonical<'tcx, ty::ParamEnvAnd<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_regions.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_regions.rs new file mode 100644 index 0000000000000..6a758a3324572 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_regions.rs @@ -0,0 +1,16 @@ +// check that we actually take into account region constraints for `ConstParamTy` impl checks + +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +struct Foo<'a>(&'a u32); + +struct Bar(T); + +impl ConstParamTy for Foo<'static> {} +impl<'a> ConstParamTy for Bar> {} +//~^ ERROR the trait `ConstParamTy` cannot be implemented for this type + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_regions.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_regions.stderr new file mode 100644 index 0000000000000..066d86b630ad7 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_regions.stderr @@ -0,0 +1,22 @@ +error[E0204]: the trait `ConstParamTy` cannot be implemented for this type + --> $DIR/const_param_ty_bad_regions.rs:13:27 + | +LL | struct Bar(T); + | - this field does not implement `ConstParamTy` +... +LL | impl<'a> ConstParamTy for Bar> {} + | ^^^^^^^^^^^^ + | +note: the `ConstParamTy` impl for `Foo<'a>` requires that `'a: 'static` + --> $DIR/const_param_ty_bad_regions.rs:10:15 + | +LL | struct Bar(T); + | ^ +help: consider restricting type parameter `'a` + | +LL | impl<'a: 'static> ConstParamTy for Bar> {} + | +++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_good_with_bounds.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_good_with_bounds.rs new file mode 100644 index 0000000000000..03ee30aad29c7 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_good_with_bounds.rs @@ -0,0 +1,21 @@ +// check-pass + +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(PartialEq, Eq)] +struct Bar; +#[derive(PartialEq, Eq)] +struct Foo(Bar); + +impl ConstParamTy for Bar +where + Foo: ConstParamTy {} + +// impl checks means that this impl is only valid if `Bar: ConstParamTy` whic +// is only valid if `Foo: ConstParamTy` holds +impl ConstParamTy for Foo {} + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_inner_ty.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_inner_ty.rs index 687296f164a51..ca9f720b4f30b 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_inner_ty.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_inner_ty.rs @@ -20,7 +20,7 @@ impl ConstParamTy for [Foo; 4] {} impl ConstParamTy for (Foo, i32, *const u8) {} //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types -//~| ERROR the trait `ConstParamTy` cannot be implemented for this type +//~| ERROR the trait `ConstParamTy` may not be implemented for this type // #119299 (ICE) diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_inner_ty.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_inner_ty.stderr index 174142442730a..c118ddbbc9b0b 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_inner_ty.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_inner_ty.stderr @@ -35,12 +35,12 @@ error: the trait `ConstParamTy` cannot be implemented for this type --> $DIR/const_param_ty_impl_bad_inner_ty.rs:10:23 | LL | struct Foo; - | ---------- this struct does not implement `ConstParamTy` + | ---------- this type does not implement `ConstParamTy` LL | LL | impl ConstParamTy for &Foo {} | ^^^^ | -help: consider annotating this struct with `#[derive(ConstParamTy)]` +help: consider annotating with `#[derive(ConstParamTy)]` | LL + #[derive(ConstParamTy)] LL | struct Foo; @@ -50,12 +50,12 @@ error: the trait `ConstParamTy` cannot be implemented for this type --> $DIR/const_param_ty_impl_bad_inner_ty.rs:13:23 | LL | struct Foo; - | ---------- this struct does not implement `ConstParamTy` + | ---------- this type does not implement `ConstParamTy` ... LL | impl ConstParamTy for &[Foo] {} | ^^^^^^ | -help: consider annotating this struct with `#[derive(ConstParamTy)]` +help: consider annotating with `#[derive(ConstParamTy)]` | LL + #[derive(ConstParamTy)] LL | struct Foo; @@ -65,31 +65,22 @@ error: the trait `ConstParamTy` cannot be implemented for this type --> $DIR/const_param_ty_impl_bad_inner_ty.rs:17:23 | LL | struct Foo; - | ---------- this struct does not implement `ConstParamTy` + | ---------- this type does not implement `ConstParamTy` ... LL | impl ConstParamTy for [Foo; 4] {} | ^^^^^^^^ | -help: consider annotating this struct with `#[derive(ConstParamTy)]` +help: consider annotating with `#[derive(ConstParamTy)]` | LL + #[derive(ConstParamTy)] LL | struct Foo; | -error: the trait `ConstParamTy` cannot be implemented for this type +error: the trait `ConstParamTy` may not be implemented for this type --> $DIR/const_param_ty_impl_bad_inner_ty.rs:21:23 | -LL | struct Foo; - | ---------- this struct does not implement `ConstParamTy` -... LL | impl ConstParamTy for (Foo, i32, *const u8) {} - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: consider annotating this struct with `#[derive(ConstParamTy)]` - | -LL + #[derive(ConstParamTy)] -LL | struct Foo; - | + | ^^^^^^^^^^^^^^^^^^^^^ the type `*const u8` is not a structure or enumeration error[E0204]: the trait `ConstParamTy` cannot be implemented for this type --> $DIR/const_param_ty_impl_bad_inner_ty.rs:30:23