Skip to content

adt_const_params: check referred-to types when checking impls of ConstParamTy on refs #120127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,16 @@ hir_analysis_const_impl_for_non_const_trait =
.note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
.adding = adding a non-const method body in the future would be a breaking change

hir_analysis_const_param_ty_impl_on_infringing_inner_ty =
the trait `ConstParamTy` cannot be implemented for this type
.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

Expand Down
43 changes: 22 additions & 21 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -962,31 +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)
}
Err(
ConstParamTyImplementationError::InfrigingFields(..)
| ConstParamTyImplementationError::InfringingInnerTy(..),
) => ty_is_local(ty),
// Implments `ConstParamTy`, suggest adding the feature to enable.
Ok(..) => true,
};
Expand Down
24 changes: 21 additions & 3 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +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_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_spans,
suggs,
}))
}
}
}
Expand Down
26 changes: 25 additions & 1 deletion compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,34 @@ 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)]
#[diag(hir_analysis_const_param_ty_impl_on_infringing_inner_ty)]
pub struct ConstParamTyImplOnInfringingInnerTy {
#[primary_span]
pub span: Span,
#[label]
pub def_spans: Vec<Span>,
#[subdiagnostic]
pub suggs: Vec<ConstParamTyImplOnInfringingInnerTySugg>,
}

#[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)]
Expand Down
Loading