Simplify some places that deal with generic parameter defaults

This commit is contained in:
León Orell Valerian Liehr 2024-11-11 18:41:27 +01:00
parent 143ce0920a
commit d0ddba3d5b
No known key found for this signature in database
GPG Key ID: D17A07215F68E713
4 changed files with 39 additions and 115 deletions

View File

@ -1427,16 +1427,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
let predicates = tcx.predicates_of(def_id.to_def_id());
let generics = tcx.generics_of(def_id);
let is_our_default = |def: &ty::GenericParamDef| match def.kind {
GenericParamDefKind::Type { has_default, .. }
| GenericParamDefKind::Const { has_default, .. } => {
has_default && def.index >= generics.parent_count as u32
}
GenericParamDefKind::Lifetime => {
span_bug!(tcx.def_span(def.def_id), "lifetime params can have no default")
}
};
// Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
// For example, this forbids the declaration:
//
@ -1444,42 +1434,23 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
//
// Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
for param in &generics.own_params {
match param.kind {
GenericParamDefKind::Type { .. } => {
if is_our_default(param) {
let ty = tcx.type_of(param.def_id).instantiate_identity();
if let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity) {
// Ignore dependent defaults -- that is, where the default of one type
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
// be sure if it will error or not as user might always specify the other.
if !ty.has_param() {
// FIXME(generic_const_exprs): This is incorrect when dealing with unused const params.
// E.g: `struct Foo<const N: usize, const M: usize = { 1 - 2 }>;`. Here, we should
// eagerly error but we don't as we have `ConstKind::Unevaluated(.., [N, M])`.
if !default.has_param() {
wfcx.register_wf_obligation(
tcx.def_span(param.def_id),
Some(WellFormedLoc::Ty(param.def_id.expect_local())),
ty.into(),
matches!(param.kind, GenericParamDefKind::Type { .. })
.then(|| WellFormedLoc::Ty(param.def_id.expect_local())),
default,
);
}
}
}
GenericParamDefKind::Const { .. } => {
if is_our_default(param) {
// FIXME(const_generics_defaults): This
// is incorrect when dealing with unused args, for example
// for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
// we should eagerly error.
let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
if !default_ct.has_param() {
wfcx.register_wf_obligation(
tcx.def_span(param.def_id),
None,
default_ct.into(),
);
}
}
}
// Doesn't have defaults.
GenericParamDefKind::Lifetime => {}
}
}
// Check that trait predicates are WF when params are instantiated with their defaults.
// We don't want to overly constrain the predicates that may be written but we want to
@ -1490,39 +1461,16 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
//
// First we build the defaulted generic parameters.
let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| {
match param.kind {
GenericParamDefKind::Lifetime => {
// All regions are identity.
tcx.mk_param_from_def(param)
}
GenericParamDefKind::Type { .. } => {
if param.index >= generics.parent_count as u32
// If the param has a default, ...
if is_our_default(param) {
let default_ty = tcx.type_of(param.def_id).instantiate_identity();
&& let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity)
// ... and it's not a dependent default, ...
if !default_ty.has_param() {
&& !default.has_param()
{
// ... then instantiate it with the default.
return default_ty.into();
return default;
}
}
tcx.mk_param_from_def(param)
}
GenericParamDefKind::Const { .. } => {
// If the param has a default, ...
if is_our_default(param) {
let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
// ... and it's not a dependent default, ...
if !default_ct.has_param() {
// ... then instantiate it with the default.
return default_ct.into();
}
}
tcx.mk_param_from_def(param)
}
}
});
// Now we build the instantiated predicates.

View File

@ -1306,33 +1306,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
)
.into(),
GenericParamDefKind::Type { has_default, .. } => {
if !infer_args && has_default {
// If we have a default, then it doesn't matter that we're not
// inferring the type arguments: we provide the default where any
// is missing.
tcx.type_of(param.def_id).instantiate(tcx, preceding_args).into()
} else {
// If no type arguments were provided, we have to infer them.
// This case also occurs as a result of some malformed input, e.g.
// a lifetime argument being given instead of a type parameter.
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
if !infer_args && let Some(default) = param.default_value(tcx) {
// If we have a default, then it doesn't matter that we're not inferring
// the type/const arguments: We provide the default where any is missing.
return default.instantiate(tcx, preceding_args);
}
// If no type/const arguments were provided, we have to infer them.
// This case also occurs as a result of some malformed input, e.g.,
// a lifetime argument being given instead of a type/const parameter.
// Using inference instead of `Error` gives better error messages.
self.fcx.var_for_def(self.span, param)
}
}
GenericParamDefKind::Const { has_default, .. } => {
if has_default {
if !infer_args {
return tcx
.const_param_default(param.def_id)
.instantiate(tcx, preceding_args)
.into();
}
}
self.fcx.var_for_def(self.span, param)
}
}
}
}

View File

@ -86,10 +86,10 @@ impl GenericParamDef {
tcx: TyCtxt<'tcx>,
) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> {
match self.kind {
GenericParamDefKind::Type { has_default, .. } if has_default => {
GenericParamDefKind::Type { has_default: true, .. } => {
Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
}
GenericParamDefKind::Const { has_default, .. } if has_default => {
GenericParamDefKind::Const { has_default: true, .. } => {
Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
}
_ => None,

View File

@ -782,21 +782,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
fn generics(&mut self) -> &mut Self {
for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
match param.kind {
GenericParamDefKind::Lifetime => {}
GenericParamDefKind::Type { has_default, .. } => {
if has_default {
if let GenericParamDefKind::Const { .. } = param.kind {
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
}
}
GenericParamDefKind::Const { has_default, .. } => {
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
if has_default {
self.visit(
self.ev.tcx.const_param_default(param.def_id).instantiate_identity(),
);
}
}
if let Some(default) = param.default_value(self.ev.tcx) {
self.visit(default.instantiate_identity());
}
}
self