Skip to content
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

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

sjwang05
Copy link
Contributor

@sjwang05 sjwang05 commented Jan 19, 2024

Previously, we didn't check if referenced-to types of impls of ConstParamTy on refs actually implemented ConstParamTy in type_allowed_to_implement_const_param_ty, leading to code like the following compiling without error (#112124):

#![feature(adt_const_params)]
#![allow(incomplete_features)]

use std::marker::ConstParamTy;

#[derive(PartialEq, Eq)]
struct Foo;

impl ConstParamTy for &Foo {}

This would lead to ICEs when the inner referenced type had fields that were not ConstParamTy and were not const-evaluatable (#119299).

This PR modifies type_allowed_to_implement_const_param_ty to check if the referred-to type and all of its fields implement ConstParamTy. It additionally adds a new variant to the ConstParamTyImplementationError enum and a new error in the case the referenced-to type does not implement ConstParamTy.

cc @rust-lang/project-const-generics

Fixes #112124

@rustbot
Copy link
Collaborator

rustbot commented Jan 19, 2024

r? @TaKO8Ki

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 19, 2024
@BoxyUwU
Copy link
Member

BoxyUwU commented Jan 19, 2024

I swear I remember writing a review that we needed to check this on the original PR 😦

@BoxyUwU
Copy link
Member

BoxyUwU commented Jan 19, 2024

Could you also do this:

Checks should also be added for tuple,array and slice element tys just to be safe imo

@BoxyUwU BoxyUwU assigned BoxyUwU and unassigned compiler-errors Jan 19, 2024
@sjwang05 sjwang05 force-pushed the issue-112124 branch 2 times, most recently from 7c61a9d to f98b06f Compare January 21, 2024 23:13
@sjwang05
Copy link
Contributor Author

Done. I split the logic into its own closure that gets called in the relevant branches, but otherwise the logic is the same as before. I also tweaked the error message slightly.

@rustbot review

@BoxyUwU
Copy link
Member

BoxyUwU commented Jan 23, 2024

Could you add the following two test cases:

// check-pass

struct Bar;
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 {}
// check that we actually take into account region constraints for `ConstParamTy` impl checks

#![feature(adt_const_params)]

use std::marker::ConstParamTy;

struct Foo<'a>(&'a u32);

struct Bar<T>(T);

impl ConstParamTy for Foo<'static> {}
impl<'a> ConstParamTy for Bar<Foo<'a>> {}
// ~^ ERROR: the trait `ConstParamTy` cannot be implemented for this type

Using an ObligationCtxt the way you are is slightly wrong and more complicated than what you're doing right now (see all_fields_implement_trait inside the nested loop for an example of what the logic roughly looks like for what you're trying to do).

Could you move the inside of the nested loop in all_fields_implement_trait to a new function fn field_implements_trait that returns the errors. Name feels a bit funny because we'll want to use it for things that arent strictly fields (i.e. the pointee type of references) but I think it's close enough to fit.

You can then use that function in type_allowed_to_implement_const_param_ty instead of setting up the ocx and infcx manually. You wouldn't need the closure once that's done as you can collect a list of tys when matching on the self ty then handle them all at once next to the all_fields_implement_trait call by iterating over them and calling field_implements_trait.

@BoxyUwU
Copy link
Member

BoxyUwU commented Jan 23, 2024

Thanks for the PR 😃 that issue has been open so long lol 😳

@sjwang05 sjwang05 force-pushed the issue-112124 branch 2 times, most recently from 8d29ae2 to eb36660 Compare January 28, 2024 00:19
@sjwang05 sjwang05 force-pushed the issue-112124 branch 2 times, most recently from 29fb9ce to 3025f6d Compare January 28, 2024 01:38
@sjwang05
Copy link
Contributor Author

Thanks for the help! I added the tests and fixed the ObligationCtxt-related code as suggested, though I feel like the implementation might be a bit messy due to us having to handle both FieldDefs and types--if you have any suggestions on how it could be improved, I'd be glad to make them. I also tweaked the error messages (again) to give slightly better errors on infringing inner tys in tuples.

@rustbot review

Copy link
Member

@BoxyUwU BoxyUwU left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There shouldn't be any need to call type_allowed_to_implement_const_param_ty (or do equivalent logic) recursively, so most of the code in the match arms should be able to be removed. I think the following changes ought to work. For impl ConstParamTy for MyType we just check all the fields implement ConstParamTy rather than checking all the fields could implement ConstParamTy so I think doing the same thing for [T]/&T/(T,) where we require T: ConstParamTy rather than T potentially being able to implement it, is okay.

Comment on lines +127 to +138
let ty = ty.peel_refs();
if !ty.has_concrete_skeleton() {
continue;
}

if let &ty::Adt(adt, args) = ty.kind() {
adts_and_args.push((adt, args));
inner_tys.push((ty, adt.did()));
} else {
type_allowed_to_implement_const_param_ty(tcx, param_env, ty, parent_cause)?;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let ty = ty.peel_refs();
if !ty.has_concrete_skeleton() {
continue;
}
if let &ty::Adt(adt, args) = ty.kind() {
adts_and_args.push((adt, args));
inner_tys.push((ty, adt.did()));
} else {
type_allowed_to_implement_const_param_ty(tcx, param_env, ty, parent_cause)?;
}
}
inner_tys.push(ty);

Comment on lines +112 to +122
let ty = ty.peel_refs();
if !ty.has_concrete_skeleton() {
return Ok(());
}

if let &ty::Adt(adt, args) = ty.kind() {
adts_and_args.push((adt, args));
inner_tys.push((ty, adt.did()));
} else {
type_allowed_to_implement_const_param_ty(tcx, param_env, ty, parent_cause)?;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let ty = ty.peel_refs();
if !ty.has_concrete_skeleton() {
return Ok(());
}
if let &ty::Adt(adt, args) = ty.kind() {
adts_and_args.push((adt, args));
inner_tys.push((ty, adt.did()));
} else {
type_allowed_to_implement_const_param_ty(tcx, param_env, ty, parent_cause)?;
}
inner_tys.push(ty);


&ty::Adt(adt, args) => (adt, args),
&ty::Adt(adt, args) => adts_and_args.push((adt, args)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
&ty::Adt(adt, args) => adts_and_args.push((adt, args)),
&ty::Adt(adt, args) => {
all_fields_implement_trait(
tcx,
param_env,
self_type,
adt,
args,
parent_cause,
hir::LangItem::ConstParamTy,
)
.map_err(ConstParamTyImplementationError::InfrigingFields)?;
}

Comment on lines +149 to +160
for (adt, args) in adts_and_args {
all_fields_implement_trait(
tcx,
param_env,
self_type,
adt,
args,
parent_cause,
hir::LangItem::ConstParamTy,
)
.map_err(ConstParamTyImplementationError::InfrigingFields)?;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (adt, args) in adts_and_args {
all_fields_implement_trait(
tcx,
param_env,
self_type,
adt,
args,
parent_cause,
hir::LangItem::ConstParamTy,
)
.map_err(ConstParamTyImplementationError::InfrigingFields)?;
}

Comment on lines +163 to +164
for (ty, def_id) in inner_tys {
let span = tcx.def_span(def_id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (ty, def_id) in inner_tys {
let span = tcx.def_span(def_id);
for ty in inner_tys {
let span = match ty.kind() {
TyKind::Adt(def, _) => tcx.def_span(def_id),
_ => parent_cause.span,
};

@BoxyUwU BoxyUwU added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 29, 2024
@bors
Copy link
Contributor

bors commented Feb 14, 2024

☔ The latest upstream changes (presumably #121018) made this pull request unmergeable. Please resolve the merge conflicts.

@JohnCSimon
Copy link
Member

@sjwang05
ping from triage - can you post your status on this PR? This PR has not received an update in a few months.

FYI: when a PR is ready for review, send a message containing
@rustbot ready to switch to S-waiting-on-review so the PR is in the reviewer's backlog.

Or if you're not going to continue, please close it. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

adt_const_params allows impls of ConstParamTy with non-ConstParamTy pointees
7 participants