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

Normalize the RHS of an Unsize goal in the new solver #113393

Merged
merged 5 commits into from
Jul 25, 2023

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Jul 6, 2023

Unsize goals are... tricky. Not only do they structurally match on their self type, but they're also structural on their other type parameter. I'm pretty certain that it is both incomplete and also just plain undesirable to not consider normalizing the RHS of an unsize goal. More practically, I'd like for this code to work:

trait A {}
trait B: A {}

impl A for usize {}
impl B for usize {}

trait Mirror {
    type Assoc: ?Sized;
}

impl<T: ?Sized> Mirror for T {
    type Assoc = T;
}

fn main() {
    // usize: Unsize<dyn B>
    let x = Box::new(1usize) as Box<<dyn B as Mirror>::Assoc>;
    // dyn A: Unsize<dyn B>
    let y = x as Box<<dyn A as Mirror>::Assoc>;
}

In order to achieve this, we add EvalCtxt::normalize_non_self_ty (naming modulo bikeshedding), which must be used for all non-self type arguments that are structurally matched in candidate assembly. Currently this is only necessary for Unsize's argument, but I could see future traits requiring this (hopefully rarely) in the future. It uses repeat_while_none to limit infinite looping, and normalizes the self type until it is no longer an alias.

Also, we need to fix feature gate detection for trait_upcasting and unsized_tuple_coercion when HIR typeck has unnormalized types. We can do that by checking the ImplSource returned by selection, which necessitates adding a new impl source for tuple upcasting.

@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. WG-trait-system-refactor The Rustc Trait System Refactor Initiative labels Jul 6, 2023
@compiler-errors compiler-errors changed the title Normalize the RHS of an Unsize goal Normalize the RHS of an Unsize goal in the new solver Jul 6, 2023
@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Jul 7, 2023

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

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jul 13, 2023
…in-selection, r=lcnr

Structurally normalize in selection

We need to do this because of the fact that we're checking the `Ty::kind` on a type during selection, but goals passed into select are not necessarily normalized.

Right now, we're (kinda) unnecessarily normalizing the RHS of a trait upcasting goal, which is broken for different reasons (rust-lang#113393). But I'm waiting for this PR to land before discussing that one.

r? `@lcnr`
@bors
Copy link
Contributor

bors commented Jul 13, 2023

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

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jul 14, 2023
…in-selection, r=lcnr

Structurally normalize in selection

We need to do this because of the fact that we're checking the `Ty::kind` on a type during selection, but goals passed into select are not necessarily normalized.

Right now, we're (kinda) unnecessarily normalizing the RHS of a trait upcasting goal, which is broken for different reasons (rust-lang#113393). But I'm waiting for this PR to land before discussing that one.

r? `@lcnr`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jul 15, 2023
…in-selection, r=lcnr

Structurally normalize in selection

We need to do this because of the fact that we're checking the `Ty::kind` on a type during selection, but goals passed into select are not necessarily normalized.

Right now, we're (kinda) unnecessarily normalizing the RHS of a trait upcasting goal, which is broken for different reasons (rust-lang#113393). But I'm waiting for this PR to land before discussing that one.

r? `@lcnr`
@rust-cloud-vms rust-cloud-vms bot force-pushed the next-solver-unsize-rhs branch 2 times, most recently from 84a2a55 to e054b79 Compare July 19, 2023 18:39
@compiler-errors compiler-errors marked this pull request as ready for review July 19, 2023 18:44
@rustbot
Copy link
Collaborator

rustbot commented Jul 19, 2023

Some changes occurred to the core trait solver

cc @rust-lang/initiative-trait-system-refactor

@compiler-errors
Copy link
Member Author

r? lcnr

Copy link
Contributor

@lcnr lcnr left a comment

Choose a reason for hiding this comment

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

vibe: instead of adding separate impl sources for "special builtin sources", would it be nicer to change impl source builtin to

Builtin(BuiltinSourceData<'tcx>, Vec<N>)`

apart from that r=me

return vec![];
};
// Need to wrap in a probe since `normalize_non_self_ty` has side-effects.
ecx.probe(|_| CandidateKind::DynUpcastingAssembly).enter(|ecx| {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this probe feels quite complex now 🤔 is there something in here that we can move into a separate function?

also realized that

trait Trait {
    fn foo(&self);
}

fn foo(x: Box<dyn Trait + Send>) -> Box<dyn Send> {
    x
}

doesn't compile, this feels like an oversight to me? 🤔 i would except us to accept this 🤔 at least unstably

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I probably just forgot to handle the "dropping principal" case. I'll have to see how the current solver handles it, and see where I forgot to do this.

Copy link
Member Author

@compiler-errors compiler-errors Jul 20, 2023

Choose a reason for hiding this comment

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

Wait, this doesn't work in the old solver either. I need to put this up in a separate PR -- while I do want to support this, it'll need T-lang FCP 🤣

@compiler-errors
Copy link
Member Author

vibe: instead of adding separate impl sources for "special builtin sources", would it be nicer to change impl source builtin to [...]

I would, and I agree that adding a new ImplSource variant is kinda ugly, but that would require maintaining two different BuiltinImplSources (or accepting the fact that some variants will go unused in certain situations). This is because some of the variants of the existing BuiltinImplSource (from the new solver) get mapped to other ImplSource variants (during selection), e.g. BuiltinImplSource::Object would not be represented as ImplSource::Builtin(BuiltinImplSource::Object, ..) but through the ImplSource::Object variant that carries vtable info.

@rust-cloud-vms rust-cloud-vms bot force-pushed the next-solver-unsize-rhs branch 2 times, most recently from 8b8198b to 71512ff Compare July 20, 2023 18:58
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

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

@lcnr lcnr left a comment

Choose a reason for hiding this comment

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

a lot of style suggestions and nits, I would love to see all of them implemented, but feel free to leave some of them as future work if you want. Going to not merge any PR which conflicts in the new solver until we land this.

@@ -172,7 +173,8 @@ impl Qualif for NeedsNonConstDrop {

if !matches!(
impl_src,
ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
ImplSource::Builtin(BuiltinImplSource::Misc, _)
Copy link
Contributor

Choose a reason for hiding this comment

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

all builtin destruct impls are not const 😅 i would like us to still use all ImplSource::Builtin in this match, or even make this exhaustive xx

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm gonna leave this here for now

Copy link
Member Author

Choose a reason for hiding this comment

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

all builtin destruct impls are not const

Also, what do you mean? They're definitely const in the old solver?

Copy link
Contributor

Choose a reason for hiding this comment

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

this is a question of what exactly this fn does... missed the double negation of 1) returning true if it is not const and 2) the ! infront of the match.

This automatically considers all builtin impls const if their source is Misc which feels like a footgun to me 🤔 anyways, const trait is a bigger issue ^^

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, sorry, I didn't understand what you meant there. Yeah, shrug... not really changing behavior here

compiler/rustc_hir_typeck/src/coercion.rs Show resolved Hide resolved
compiler/rustc_middle/src/traits/mod.rs Outdated Show resolved Hide resolved
compiler/rustc_middle/src/traits/mod.rs Outdated Show resolved Hide resolved
compiler/rustc_middle/src/traits/structural_impls.rs Outdated Show resolved Hide resolved
compiler/rustc_trait_selection/src/solve/trait_goals.rs Outdated Show resolved Hide resolved
Comment on lines 482 to 484
param_env: ty::ParamEnv<'tcx>,
a_ty: Ty<'tcx>,
b_ty: Ty<'tcx>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
param_env: ty::ParamEnv<'tcx>,
a_ty: Ty<'tcx>,
b_ty: Ty<'tcx>,
goal: Goal<'tcx, (Ty<'tcx, Ty<'tcx>)>,

🤔 and then let (a, b) = goal.predicate;

Copy link
Contributor

Choose a reason for hiding this comment

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

vibe: maybe this match should live in consider_builtin_unsize_and_upcast_candidates and we probe in the match relevant match arms?

Copy link
Member Author

@compiler-errors compiler-errors Jul 25, 2023

Choose a reason for hiding this comment

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

I don't really know what you're asking for in that "vibe" comment lol

Copy link
Contributor

Choose a reason for hiding this comment

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

instead of calling consider_builtin_unsize_candidate and consider_builtin_upcast_candidates for all a and b and then matching in each function individually, match on a and b in consider_builtin_unsize_and_upcast_candidates... I guess merge unsize and upcast builtin impls back together completely 😅

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, I just thought the nesting was getting kinda gnarly when they were in one method. Yeah, I guess I can try that.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess maybe move bigger match branches into separate functions, so we'd have consider_trait_upcast_candidates, consider_tuple_unsize_candidate and so on

Copy link
Member Author

Choose a reason for hiding this comment

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

That refactoring work is literally miserable actually, lol. I'm gonna do this in a follow-up, I don't think the current split we have right now is that different from what we currently have -- you're essentially just asking to break up consider_builtin_unsize_candidate.

compiler/rustc_trait_selection/src/solve/trait_goals.rs Outdated Show resolved Hide resolved
@@ -48,12 +48,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut impl_src = match candidate {
BuiltinCandidate { has_nested } => {
Copy link
Contributor

Choose a reason for hiding this comment

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

for future PR, we should do the same for old style candidates 😁

have BuiltinCandidate with a CandidateKind. Definitely not in this PR

@rustbot
Copy link
Collaborator

rustbot commented Jul 25, 2023

Some changes occurred in abstract_const.rs

cc @BoxyUwU

Some changes occurred to the CTFE / Miri engine

cc @rust-lang/miri

// FIXME: We only need to do *any* of this if we're considering a trait goal,
// since we don't need to look at any supertrait or anything if we are doing
// a projection goal.
if let Some(principal) = bounds.principal() {
Copy link
Contributor

Choose a reason for hiding this comment

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

will maybe look at this myself in a separate PR, but this would be in the ExistentialPredicate::Trait match arm instead 🤷

Copy link
Member Author

Choose a reason for hiding this comment

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

Only realized what you meant here after the PR. Yeah, if you want to follow-up with this and any other structural changes you'd like to see about this code, I'd be glad to review it.

@@ -404,20 +526,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
// Check that the type implements all of the predicates of the def-id.
// (i.e. the principal, all of the associated types match, and any auto traits)
ecx.add_goals(
data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
data.iter()
.map(|pred| Goal::new(tcx, param_env, pred.with_self_ty(tcx, a_ty))),
Copy link
Contributor

Choose a reason for hiding this comment

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

suggested to use goal as an arg to use goal.with here, will experiment a bit with the code layout myself here after this is merged

@lcnr
Copy link
Contributor

lcnr commented Jul 25, 2023

@bors r+ rollup=never likely to get merge conflicts

@bors
Copy link
Contributor

bors commented Jul 25, 2023

📌 Commit a7ed9c1 has been approved by lcnr

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 25, 2023
@bors
Copy link
Contributor

bors commented Jul 25, 2023

⌛ Testing commit a7ed9c1 with merge 8327047...

@bors
Copy link
Contributor

bors commented Jul 25, 2023

☀️ Test successful - checks-actions
Approved by: lcnr
Pushing 8327047 to master...

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (8327047): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-4.0% [-4.0%, -4.0%] 1
All ❌✅ (primary) - - 0

Cycles

This benchmark run did not return any relevant results for this metric.

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 650.083s -> 650.593s (0.08%)

flip1995 pushed a commit to flip1995/rust that referenced this pull request Jul 31, 2023
…hs, r=lcnr

Normalize the RHS of an `Unsize` goal in the new solver

`Unsize` goals are... tricky. Not only do they structurally match on their self type, but they're also structural on their other type parameter. I'm pretty certain that it is both incomplete and also just plain undesirable to not consider normalizing the RHS of an unsize goal. More practically, I'd like for this code to work:

```rust
trait A {}
trait B: A {}

impl A for usize {}
impl B for usize {}

trait Mirror {
    type Assoc: ?Sized;
}

impl<T: ?Sized> Mirror for T {
    type Assoc = T;
}

fn main() {
    // usize: Unsize<dyn B>
    let x = Box::new(1usize) as Box<<dyn B as Mirror>::Assoc>;
    // dyn A: Unsize<dyn B>
    let y = x as Box<<dyn A as Mirror>::Assoc>;
}
```

---

In order to achieve this, we add `EvalCtxt::normalize_non_self_ty` (naming modulo bikeshedding), which *must* be used for all non-self type arguments that are structurally matched in candidate assembly. Currently this is only necessary for `Unsize`'s argument, but I could see future traits requiring this (hopefully rarely) in the future. It uses `repeat_while_none` to limit infinite looping, and normalizes the self type until it is no longer an alias.

Also, we need to fix feature gate detection for `trait_upcasting` and `unsized_tuple_coercion` when HIR typeck has unnormalized types. We can do that by checking the `ImplSource` returned by selection, which necessitates adding a new impl source for tuple upcasting.
@compiler-errors compiler-errors deleted the next-solver-unsize-rhs branch August 9, 2023 05:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants