Skip to content

Commit b727132

Browse files
authored
Rollup merge of #108161 - WaffleLapkin:const_param_ty, r=BoxyUwU
Add `ConstParamTy` trait This is a bit sketch, but idk. r? `@BoxyUwU` Yet to be done: - [x] ~~Figure out if it's okay to implement `StructuralEq` for primitives / possibly remove their special casing~~ (it should be okay, but maybe not in this PR...) - [ ] Maybe refactor the code a little bit - [x] Use a macro to make impls a bit nicer Future work: - [ ] Actually™ use the trait when checking if a `const` generic type is allowed - [ ] _Really_ refactor the surrounding code - [ ] Refactor `marker.rs` into multiple modules for each "theme" of markers
2 parents f916c44 + c317546 commit b727132

23 files changed

+673
-179
lines changed

compiler/rustc_hir/src/lang_items.rs

+2
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,8 @@ language_item_table! {
293293

294294
PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
295295

296+
ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);
297+
296298
Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None;
297299
PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
298300
PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None;

compiler/rustc_hir_analysis/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ hir_analysis_field_already_declared =
3535
3636
hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
3737
38+
hir_analysis_const_param_ty_impl_on_non_adt =
39+
the trait `ConstParamTy` may not be implemented for this type
40+
.label = type is not a structure or enumeration
41+
3842
hir_analysis_ambiguous_lifetime_bound =
3943
ambiguous lifetime bound, explicit lifetime bound required
4044

compiler/rustc_hir_analysis/src/coherence/builtin.rs

+148-107
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
//! Check properties that are required by built-in traits and set
22
//! up data structures required by type-checking/codegen.
33
4-
use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
4+
use crate::errors::{
5+
ConstParamTyImplOnNonAdt, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem,
6+
};
57
use rustc_data_structures::fx::FxHashSet;
6-
use rustc_errors::{struct_span_err, MultiSpan};
8+
use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan};
79
use rustc_hir as hir;
810
use rustc_hir::def_id::{DefId, LocalDefId};
911
use rustc_hir::lang_items::LangItem;
@@ -14,9 +16,11 @@ use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
1416
use rustc_infer::traits::Obligation;
1517
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
1618
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
19+
use rustc_span::Span;
1720
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
1821
use rustc_trait_selection::traits::misc::{
19-
type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
22+
type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
23+
ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
2024
};
2125
use rustc_trait_selection::traits::ObligationCtxt;
2226
use rustc_trait_selection::traits::{self, ObligationCause};
@@ -27,6 +31,7 @@ pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
2731
Checker { tcx, trait_def_id }
2832
.check(lang_items.drop_trait(), visit_implementation_of_drop)
2933
.check(lang_items.copy_trait(), visit_implementation_of_copy)
34+
.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty)
3035
.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
3136
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
3237
}
@@ -83,110 +88,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
8388
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
8489
Ok(()) => {}
8590
Err(CopyImplementationError::InfringingFields(fields)) => {
86-
let mut err = struct_span_err!(
87-
tcx.sess,
88-
span,
89-
E0204,
90-
"the trait `Copy` cannot be implemented for this type"
91-
);
92-
93-
// We'll try to suggest constraining type parameters to fulfill the requirements of
94-
// their `Copy` implementation.
95-
let mut errors: BTreeMap<_, Vec<_>> = Default::default();
96-
let mut bounds = vec![];
97-
98-
let mut seen_tys = FxHashSet::default();
99-
100-
for (field, ty, reason) in fields {
101-
// Only report an error once per type.
102-
if !seen_tys.insert(ty) {
103-
continue;
104-
}
105-
106-
let field_span = tcx.def_span(field.did);
107-
err.span_label(field_span, "this field does not implement `Copy`");
108-
109-
match reason {
110-
InfringingFieldsReason::Fulfill(fulfillment_errors) => {
111-
for error in fulfillment_errors {
112-
let error_predicate = error.obligation.predicate;
113-
// Only note if it's not the root obligation, otherwise it's trivial and
114-
// should be self-explanatory (i.e. a field literally doesn't implement Copy).
115-
116-
// FIXME: This error could be more descriptive, especially if the error_predicate
117-
// contains a foreign type or if it's a deeply nested type...
118-
if error_predicate != error.root_obligation.predicate {
119-
errors
120-
.entry((ty.to_string(), error_predicate.to_string()))
121-
.or_default()
122-
.push(error.obligation.cause.span);
123-
}
124-
if let ty::PredicateKind::Clause(ty::Clause::Trait(
125-
ty::TraitPredicate {
126-
trait_ref,
127-
polarity: ty::ImplPolarity::Positive,
128-
..
129-
},
130-
)) = error_predicate.kind().skip_binder()
131-
{
132-
let ty = trait_ref.self_ty();
133-
if let ty::Param(_) = ty.kind() {
134-
bounds.push((
135-
format!("{ty}"),
136-
trait_ref.print_only_trait_path().to_string(),
137-
Some(trait_ref.def_id),
138-
));
139-
}
140-
}
141-
}
142-
}
143-
InfringingFieldsReason::Regions(region_errors) => {
144-
for error in region_errors {
145-
let ty = ty.to_string();
146-
match error {
147-
RegionResolutionError::ConcreteFailure(origin, a, b) => {
148-
let predicate = format!("{b}: {a}");
149-
errors
150-
.entry((ty.clone(), predicate.clone()))
151-
.or_default()
152-
.push(origin.span());
153-
if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
154-
bounds.push((b.to_string(), a.to_string(), None));
155-
}
156-
}
157-
RegionResolutionError::GenericBoundFailure(origin, a, b) => {
158-
let predicate = format!("{a}: {b}");
159-
errors
160-
.entry((ty.clone(), predicate.clone()))
161-
.or_default()
162-
.push(origin.span());
163-
if let infer::region_constraints::GenericKind::Param(_) = a {
164-
bounds.push((a.to_string(), b.to_string(), None));
165-
}
166-
}
167-
_ => continue,
168-
}
169-
}
170-
}
171-
}
172-
}
173-
for ((ty, error_predicate), spans) in errors {
174-
let span: MultiSpan = spans.into();
175-
err.span_note(
176-
span,
177-
&format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
178-
);
179-
}
180-
suggest_constraining_type_params(
181-
tcx,
182-
tcx.hir().get_generics(impl_did).expect("impls always have generics"),
183-
&mut err,
184-
bounds.iter().map(|(param, constraint, def_id)| {
185-
(param.as_str(), constraint.as_str(), *def_id)
186-
}),
187-
None,
188-
);
189-
err.emit();
91+
infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
19092
}
19193
Err(CopyImplementationError::NotAnAdt) => {
19294
tcx.sess.emit_err(CopyImplOnNonAdt { span });
@@ -197,6 +99,29 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
19799
}
198100
}
199101

102+
fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
103+
let self_type = tcx.type_of(impl_did).subst_identity();
104+
assert!(!self_type.has_escaping_bound_vars());
105+
106+
let param_env = tcx.param_env(impl_did);
107+
108+
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
109+
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
110+
impl_ => impl_.self_ty.span,
111+
};
112+
113+
let cause = traits::ObligationCause::misc(span, impl_did);
114+
match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
115+
Ok(()) => {}
116+
Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
117+
infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
118+
}
119+
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
120+
tcx.sess.emit_err(ConstParamTyImplOnNonAdt { span });
121+
}
122+
}
123+
}
124+
200125
fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
201126
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
202127

@@ -593,3 +518,119 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
593518

594519
CoerceUnsizedInfo { custom_kind: kind }
595520
}
521+
522+
fn infringing_fields_error(
523+
tcx: TyCtxt<'_>,
524+
fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>,
525+
lang_item: LangItem,
526+
impl_did: LocalDefId,
527+
impl_span: Span,
528+
) -> ErrorGuaranteed {
529+
let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
530+
531+
let trait_name = tcx.def_path_str(trait_did);
532+
533+
let mut err = struct_span_err!(
534+
tcx.sess,
535+
impl_span,
536+
E0204,
537+
"the trait `{trait_name}` cannot be implemented for this type"
538+
);
539+
540+
// We'll try to suggest constraining type parameters to fulfill the requirements of
541+
// their `Copy` implementation.
542+
let mut errors: BTreeMap<_, Vec<_>> = Default::default();
543+
let mut bounds = vec![];
544+
545+
let mut seen_tys = FxHashSet::default();
546+
547+
for (field, ty, reason) in fields {
548+
// Only report an error once per type.
549+
if !seen_tys.insert(ty) {
550+
continue;
551+
}
552+
553+
let field_span = tcx.def_span(field.did);
554+
err.span_label(field_span, format!("this field does not implement `{trait_name}`"));
555+
556+
match reason {
557+
InfringingFieldsReason::Fulfill(fulfillment_errors) => {
558+
for error in fulfillment_errors {
559+
let error_predicate = error.obligation.predicate;
560+
// Only note if it's not the root obligation, otherwise it's trivial and
561+
// should be self-explanatory (i.e. a field literally doesn't implement Copy).
562+
563+
// FIXME: This error could be more descriptive, especially if the error_predicate
564+
// contains a foreign type or if it's a deeply nested type...
565+
if error_predicate != error.root_obligation.predicate {
566+
errors
567+
.entry((ty.to_string(), error_predicate.to_string()))
568+
.or_default()
569+
.push(error.obligation.cause.span);
570+
}
571+
if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
572+
trait_ref,
573+
polarity: ty::ImplPolarity::Positive,
574+
..
575+
})) = error_predicate.kind().skip_binder()
576+
{
577+
let ty = trait_ref.self_ty();
578+
if let ty::Param(_) = ty.kind() {
579+
bounds.push((
580+
format!("{ty}"),
581+
trait_ref.print_only_trait_path().to_string(),
582+
Some(trait_ref.def_id),
583+
));
584+
}
585+
}
586+
}
587+
}
588+
InfringingFieldsReason::Regions(region_errors) => {
589+
for error in region_errors {
590+
let ty = ty.to_string();
591+
match error {
592+
RegionResolutionError::ConcreteFailure(origin, a, b) => {
593+
let predicate = format!("{b}: {a}");
594+
errors
595+
.entry((ty.clone(), predicate.clone()))
596+
.or_default()
597+
.push(origin.span());
598+
if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
599+
bounds.push((b.to_string(), a.to_string(), None));
600+
}
601+
}
602+
RegionResolutionError::GenericBoundFailure(origin, a, b) => {
603+
let predicate = format!("{a}: {b}");
604+
errors
605+
.entry((ty.clone(), predicate.clone()))
606+
.or_default()
607+
.push(origin.span());
608+
if let infer::region_constraints::GenericKind::Param(_) = a {
609+
bounds.push((a.to_string(), b.to_string(), None));
610+
}
611+
}
612+
_ => continue,
613+
}
614+
}
615+
}
616+
}
617+
}
618+
for ((ty, error_predicate), spans) in errors {
619+
let span: MultiSpan = spans.into();
620+
err.span_note(
621+
span,
622+
format!("the `{trait_name}` impl for `{ty}` requires that `{error_predicate}`"),
623+
);
624+
}
625+
suggest_constraining_type_params(
626+
tcx,
627+
tcx.hir().get_generics(impl_did).expect("impls always have generics"),
628+
&mut err,
629+
bounds
630+
.iter()
631+
.map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
632+
None,
633+
);
634+
635+
err.emit()
636+
}

compiler/rustc_hir_analysis/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ pub struct CopyImplOnNonAdt {
107107
pub span: Span,
108108
}
109109

110+
#[derive(Diagnostic)]
111+
#[diag(hir_analysis_const_param_ty_impl_on_non_adt)]
112+
pub struct ConstParamTyImplOnNonAdt {
113+
#[primary_span]
114+
#[label]
115+
pub span: Span,
116+
}
117+
110118
#[derive(Diagnostic)]
111119
#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")]
112120
pub struct TraitObjectDeclaredWithNoTraits {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ symbols! {
531531
const_mut_refs,
532532
const_panic,
533533
const_panic_fmt,
534+
const_param_ty,
534535
const_precise_live_drops,
535536
const_raw_ptr_deref,
536537
const_raw_ptr_to_usize_cast,

0 commit comments

Comments
 (0)