Skip to content

nll-relate: improve hr opaque types support #142079

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_borrowck/src/handle_placeholders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ impl RegionTracker {
self.max_nameable_universe
}

pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex {
self.max_placeholder_universe_reached
}

fn merge_min_max_seen(&mut self, other: &Self) {
self.max_placeholder_universe_reached = std::cmp::max(
self.max_placeholder_universe_reached,
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {

// If the member region lives in a higher universe, we currently choose
// the most conservative option by leaving it unchanged.
if !self.max_nameable_universe(scc).is_root() {
if !self.max_placeholder_universe_reached(scc).is_root() {
return;
}

Expand Down Expand Up @@ -1376,6 +1376,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.scc_annotations[scc].max_nameable_universe()
}

pub(crate) fn max_placeholder_universe_reached(
&self,
scc: ConstraintSccIndex,
) -> UniverseIndex {
self.scc_annotations[scc].max_placeholder_universe_reached()
}

/// Checks the final value for the free region `fr` to see if it
/// grew too large. In particular, examine what `end(X)` points
/// wound up in `fr`'s final value; for each `end(X)` where `X !=
Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_borrowck/src/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,13 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
// by using `ty_vid rel B` and then finally and end by equating `ty_vid` to
// the opaque.
let mut enable_subtyping = |ty, opaque_is_expected| {
let ty_vid = infcx.next_ty_var_id_in_universe(self.span(), ty::UniverseIndex::ROOT);

// We create the fresh inference variable in the highest universe.
// In theory we could limit it to the highest universe in the args of
// the opaque but that isn't really worth the effort.
//
// We'll make sure that the opaque type can actually name everything
// in its hidden type later on.
let ty_vid = infcx.next_ty_vid(self.span());
let variance = if opaque_is_expected {
self.ambient_variance
} else {
Expand Down
22 changes: 15 additions & 7 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,22 +743,30 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().type_variables().num_vars()
}

pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> {
self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None })
pub fn next_ty_vid(&self, span: Span) -> TyVid {
self.next_ty_vid_with_origin(TypeVariableOrigin { span, param_def_id: None })
}

pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin);
Ty::new_var(self.tcx, vid)
pub fn next_ty_vid_with_origin(&self, origin: TypeVariableOrigin) -> TyVid {
self.inner.borrow_mut().type_variables().new_var(self.universe(), origin)
}

pub fn next_ty_var_id_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid {
pub fn next_ty_vid_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid {
let origin = TypeVariableOrigin { span, param_def_id: None };
self.inner.borrow_mut().type_variables().new_var(universe, origin)
}

pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> {
self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None })
}

pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
let vid = self.next_ty_vid_with_origin(origin);
Ty::new_var(self.tcx, vid)
}

pub fn next_ty_var_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> Ty<'tcx> {
let vid = self.next_ty_var_id_in_universe(span, universe);
let vid = self.next_ty_vid_in_universe(span, universe);
Ty::new_var(self.tcx, vid)
}

Expand Down
29 changes: 29 additions & 0 deletions tests/ui/nll/member-constraints/non-root-universe-existential-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

trait Proj<'a> {
type Assoc;
}

impl<'a, 'b, F: FnOnce() -> &'b ()> Proj<'a> for F {
type Assoc = ();
}

fn is_proj<F: for<'a> Proj<'a>>(f: F) {}

fn define<'a>() -> impl Sized + use<'a> {
// This defines the RPIT to `&'unconstrained_b ()`, an inference
// variable which is in a higher universe as gets created inside
// of the binder of `F: for<'a> Proj<'a>`. This previously caused
// us to not apply member constraints.
//
// This was unnecessary. It is totally acceptable for member regions
// to be able to name placeholders from higher universes, as long as
// they don't actually do so.
is_proj(define::<'a>);
&()
}

fn main() {}
31 changes: 31 additions & 0 deletions tests/ui/nll/member-constraints/non-root-universe-existential-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//@ check-pass

// Unlike `non-root-universe-existential-1.rs` this previously
// compiled as it simnply didn't define the hidden type of
// `impl Iterator` when projecting through it. We will do so
// with the new solver. Further minimizing this is challenging.

struct Type(Vec<Type>);
enum TypeTreeValueIter<'a, T> {
Once(T),
Ref(&'a ()),
}

impl<'a, T> Iterator for TypeTreeValueIter<'a, T> {
type Item = T;

fn next(&mut self) -> Option<Self::Item> {
loop {}
}
}

fn item<I: Iterator<Item: Iterator>>(x: I) -> <I::Item as Iterator>::Item {
loop {}
}

fn get_type_tree_values<'a>(ty: &'a Type) -> impl Iterator<Item = &'a Type> {
let _: &'a Type = item(std::iter::once(ty).map(get_type_tree_values));
TypeTreeValueIter::<'a, &'a Type>::Once(ty)
}

fn main() {}
3 changes: 1 addition & 2 deletions tests/ui/type-alias-impl-trait/higher_kinded_params3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ type Successors<'a> = impl std::fmt::Debug + 'a;
impl Terminator {
#[define_opaque(Successors, Tait)]
fn successors(&self, mut f: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> {
f = g;
//~^ ERROR mismatched types
f = g; //~ ERROR expected generic lifetime parameter, found `'x`
}
}

Expand Down
11 changes: 4 additions & 7 deletions tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
error[E0308]: mismatched types
error[E0792]: expected generic lifetime parameter, found `'x`
--> $DIR/higher_kinded_params3.rs:27:9
|
LL | type Tait<'a> = impl std::fmt::Debug + 'a;
| ------------------------- the expected opaque type
| -- this generic parameter must be used with a generic lifetime parameter
...
LL | f = g;
| ^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'x> fn(&'x ()) -> Tait<'x>`
found fn pointer `for<'a> fn(&'a ()) -> &'a ()`
| ^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0792`.
2 changes: 1 addition & 1 deletion tests/ui/type-alias-impl-trait/hkl_forbidden3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn foo<'a>(x: &'a ()) -> &'a () {

#[define_opaque(Opaque)]
fn test() -> for<'a> fn(&'a ()) -> Opaque<'a> {
foo //~ ERROR: mismatched types
foo //~ ERROR: expected generic lifetime parameter, found `'a`
}

fn main() {}
11 changes: 4 additions & 7 deletions tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
error[E0308]: mismatched types
error[E0792]: expected generic lifetime parameter, found `'a`
--> $DIR/hkl_forbidden3.rs:11:5
|
LL | type Opaque<'a> = impl Sized + 'a;
| --------------- the expected opaque type
| -- this generic parameter must be used with a generic lifetime parameter
...
LL | foo
| ^^^ one type is more general than the other
|
= note: expected fn pointer `for<'a> fn(&'a ()) -> Opaque<'a>`
found fn pointer `for<'a> fn(&'a ()) -> &'a ()`
| ^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0792`.
Loading