owned this note
owned this note
Published
Linked with GitHub
*trying to define the "next solver idealized behavior" (NSIB) and any add-ons to maintain backwards compatability and to continue supporting desired patterns: NSIB+*
# NSIB
## opaques are alias types
Opaque types are treated the same as other aliases, most notabily associated types, whenever possible. There should be as few divergences in behavior as possible.
This is desirable, as they are very similar to other alias types, in that they can be normalized to their hidden type and also have the same requirements for completeness. Treating them this way also reduces the complexity of the type system by sharing code. Having to deal with opaque types separately results in more complex rules and new kinds of interactions. As we need to treat them like other aliases in the implicit-negative mode, having significant differences between modes also adds complexity.
*is there an alternative approach here, maybe by treating them more like rigid types with more limited places to instantiate them? they would still have to be ordinary aliases during coherence*
### `normalizes-to` for opaques
https://github.com/rust-lang/rust/blob/09d73fab0823ecddd5e67e042cd0de3863c3d501/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs#L13-L16
`normalizes-to` is used to define the one-step normalization behavior for aliases in the new solver: `<<T as IdInner>::Assoc as IdOuter>::Assoc` first normalizes to `<T as IdInner>::Assoc` which then normalizes to `T`. It takes both the `AliasTy` which is getting normalized and the expected `Term`. To use `normalizes-to` for actual normalization, the expected term can simply be an unconstrained inference variable.
For opaque types in the defining scope and in the implicit-negative coherence mode, this is always done in two steps. Outside of the defining scope `normalizes-to` for opaques always returns `Err(NoSolution)`.
We start by trying to to assign the expected type as a hidden type.
In the implicit-negative coherence mode, this currently always results in ambiguity without interacting with the opaque types storage. We could instead add allow 'defining' all opaque types, discarding their inferred types at the end, changing the behavior of an opaque type is used multiple times during coherence: [example](https://github.com/rust-lang/rust/blob/master/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs).
Inside of the defining scope we start by checking whether the type and const arguments of the opaque are all placeholders: [source](https://github.com/rust-lang/rust/blob/bc1b9e0e9a813d27a09708b293dc2d41c472f0d0/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs#L32-L43). If this check is ambiguous, return ambiguity, if it fails, return `Err(NoSolution)`. This check ignores regions which are only checked at the end of borrowck. If it succeeds, continue.
We then check whether we're able to *semantically* unify the generic arguments of the opaque with the arguments of any opaque type already in the opaque types storage: [source](https://github.com/rust-lang/rust/blob/bc1b9e0e9a813d27a09708b293dc2d41c472f0d0/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs#L51-L59).
If so, we unify the previously stored type with the expected type of this `normalizes-to` call: [source](https://github.com/rust-lang/rust/blob/bc1b9e0e9a813d27a09708b293dc2d41c472f0d0/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs#L51-L59)[^1]. If not, we insert the expected type in the opaque types storage: [source](https://github.com/rust-lang/rust/blob/bc1b9e0e9a813d27a09708b293dc2d41c472f0d0/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs#L61-L78)[^2].
Finally, we check whether the item bounds of the opaque hold for the expected type: [source](https://github.com/rust-lang/rust/blob/bc1b9e0e9a813d27a09708b293dc2d41c472f0d0/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs#L79-L84)[^3].
[^1]: FIXME: this should ideally only result in a unique candidate given that we require the args to be placeholders and regions are always inference vars
[^2]: FIXME: why do we check whether the expected type is rigid for this.
[^3]: FIXME: i think we should always add the item bounds, right now we only do so when first defining the opaque type? isn't that an issue by calling
### using alias-bounds of normalizable aliases
https://github.com/rust-lang/trait-system-refactor-initiative/issues/77
Using an `AliasBound` candidate for normalizable aliases is generally not possible as an associated type can have stronger bounds then the resulting type when normalizing via a `ParamEnv` candidate.
This also means whether we eagerly normalized a type is pretty much unobservable. Using `AliasBound` candidates of normalizeable aliases causes our exact normalization strategy is user-facing. Where we normalize is something we likely want to change that after removing support for the old solver, so that would be undesirable.
## opaque types can be defined anywhere
Opaque types in their defining-scope can be defined anywhere, whether when simply relating types or in the trait solver. This removes order dependence and incompleteness. Without this the result of a goal can differ due to subtle reasons, e.g. whether we try to evaluate a goal using the opaque before the first defining use of the opaque.
## higher ranked opaque types in their defining scope
These are not supported and trying to define them right now should always error.
FIXME: Because looking up opaque types in the opaque type storage can now unify regions, we have to eagerly check that the opaque types does not reference placeholders. We otherwise end up leaking placeholders.
## member constraints
described here https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/member_constraints.html
# MSIB+
## calling methods on opaque types
TODO
## remaining open questions
### opaque types in astconv
should astconv use the alias-bounds of the opaque inside of the defining scope
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=930eeb8705dc711c7f13bc2ef6599e65
https://rust.godbolt.org/z/zbY3raz5a
### look through all uses of `ty::Opaque` in the type system
TODO: How are they handled in `coerce`?
TODO