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

Rollup of 8 pull requests #119630

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5c0e62c
Hide foreign `#[doc(hidden)]` paths in import suggestions
Jules-Bertholet Dec 20, 2023
5f56465
Make feature `negative_bounds` internal
fmease Dec 27, 2023
a251974
Deny parenthetical notation for negative bounds
fmease Dec 27, 2023
32cea61
Don't elaborate `!Sized` to `!Sized + Sized`
fmease Dec 27, 2023
977546d
rustc_middle: Pretty-print negative bounds correctly
fmease Dec 27, 2023
90d6fe2
Imply outlives-bounds on lazy type aliases
fmease Dec 27, 2023
1d48f69
Check yield terminator's resume type in borrowck
compiler-errors Jan 4, 2024
4bc3552
cstore: Remove unnecessary locking from `CrateMetadata`
petrochenkov Jan 4, 2024
407cb24
Remove `hir::Guard`
matthewjasper Sep 21, 2023
a549711
Remove `thir::Guard`
matthewjasper Sep 21, 2023
1a267e3
Restore if let guard temporary scoping difference
matthewjasper Jan 3, 2024
44bba54
Update clippy for hir::Guard removal
matthewjasper Jan 4, 2024
6a2bd5a
Use `resolutions(()).effective_visiblities` to avoid cycle errors
compiler-errors Jan 4, 2024
fdb70da
Add support for shell argfiles
djkoloski Dec 6, 2023
a721ccb
Rollup merge of #118680 - djkoloski:shell_argfiles, r=compiler-errors
matthiaskrgr Jan 5, 2024
7a00ce6
Rollup merge of #119151 - Jules-Bertholet:no-foreign-doc-hidden-sugge…
matthiaskrgr Jan 5, 2024
7e58b2f
Rollup merge of #119350 - fmease:lazy-ty-aliases-implied-bounds, r=co…
matthiaskrgr Jan 5, 2024
e0c86de
Rollup merge of #119354 - fmease:negative_bounds-fixes, r=compiler-er…
matthiaskrgr Jan 5, 2024
dd6b824
Rollup merge of #119506 - compiler-errors:visibilities-for-object-saf…
matthiaskrgr Jan 5, 2024
29a1770
Rollup merge of #119554 - matthewjasper:remove-guard-distinction, r=c…
matthiaskrgr Jan 5, 2024
ebbe615
Rollup merge of #119563 - compiler-errors:coroutine-resume, r=oli-obk
matthiaskrgr Jan 5, 2024
b4a7f1e
Rollup merge of #119589 - petrochenkov:cdatalock, r=Mark-Simulacrum
matthiaskrgr Jan 5, 2024
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
Prev Previous commit
Next Next commit
Imply outlives-bounds on lazy type aliases
  • Loading branch information
fmease committed Dec 28, 2023
commit 90d6fe2cba2b621b4fc331a1f6dd67c63a7c1033
179 changes: 108 additions & 71 deletions compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ pub(super) fn infer_predicates(
}
}

DefKind::TyAlias if tcx.type_alias_is_lazy(item_did) => {
insert_required_predicates_to_be_wf(
tcx,
tcx.type_of(item_did).instantiate_identity(),
tcx.def_span(item_did),
&global_inferred_outlives,
&mut item_required_predicates,
&mut explicit_map,
);
}

_ => {}
};

Expand Down Expand Up @@ -88,78 +99,41 @@ pub(super) fn infer_predicates(

fn insert_required_predicates_to_be_wf<'tcx>(
tcx: TyCtxt<'tcx>,
field_ty: Ty<'tcx>,
field_span: Span,
ty: Ty<'tcx>,
span: Span,
global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
) {
for arg in field_ty.walk() {
let ty = match arg.unpack() {
for arg in ty.walk() {
let leaf_ty = match arg.unpack() {
GenericArgKind::Type(ty) => ty,

// No predicates from lifetimes or constants, except potentially
// constants' types, but `walk` will get to them as well.
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
};

match *ty.kind() {
// The field is of type &'a T which means that we will have
// a predicate requirement of T: 'a (T outlives 'a).
//
// We also want to calculate potential predicates for the T
match *leaf_ty.kind() {
ty::Ref(region, rty, _) => {
// The type is `&'a T` which means that we will have
// a predicate requirement of `T: 'a` (`T` outlives `'a`).
//
// We also want to calculate potential predicates for the `T`.
debug!("Ref");
insert_outlives_predicate(tcx, rty.into(), region, field_span, required_predicates);
insert_outlives_predicate(tcx, rty.into(), region, span, required_predicates);
}

// For each Adt (struct/enum/union) type `Foo<'a, T>`, we
// can load the current set of inferred and explicit
// predicates from `global_inferred_outlives` and filter the
// ones that are TypeOutlives.
ty::Adt(def, args) => {
// First check the inferred predicates
//
// Example 1:
//
// struct Foo<'a, T> {
// field1: Bar<'a, T>
// }
//
// struct Bar<'b, U> {
// field2: &'b U
// }
//
// Here, when processing the type of `field1`, we would
// request the set of implicit predicates computed for `Bar`
// thus far. This will initially come back empty, but in next
// round we will get `U: 'b`. We then apply the substitution
// `['b => 'a, U => T]` and thus get the requirement that `T:
// 'a` holds for `Foo`.
// For ADTs (structs/enums/unions), we check inferred and explicit predicates.
debug!("Adt");
if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) {
for (unsubstituted_predicate, &span) in
unsubstituted_predicates.as_ref().skip_binder()
{
// `unsubstituted_predicate` is `U: 'b` in the
// example above. So apply the substitution to
// get `T: 'a` (or `predicate`):
let predicate = unsubstituted_predicates
.rebind(*unsubstituted_predicate)
.instantiate(tcx, args);
insert_outlives_predicate(
tcx,
predicate.0,
predicate.1,
span,
required_predicates,
);
}
}

// Check if the type has any explicit predicates that need
// to be added to `required_predicates`
// let _: () = args.region_at(0);
check_inferred_predicates(
tcx,
def.did(),
args,
global_inferred_outlives,
required_predicates,
);
check_explicit_predicates(
tcx,
def.did(),
Expand All @@ -170,13 +144,31 @@ fn insert_required_predicates_to_be_wf<'tcx>(
);
}

ty::Alias(ty::Weak, alias) => {
// This corresponds to a type like `Type<'a, T>`.
// We check inferred and explicit predicates.
debug!("Weak");
check_inferred_predicates(
tcx,
alias.def_id,
alias.args,
global_inferred_outlives,
required_predicates,
);
check_explicit_predicates(
tcx,
alias.def_id,
alias.args,
required_predicates,
explicit_map,
None,
);
}

ty::Dynamic(obj, ..) => {
// This corresponds to `dyn Trait<..>`. In this case, we should
// use the explicit predicates as well.

debug!("Dynamic");
debug!("field_ty = {}", &field_ty);
debug!("ty in field = {}", &ty);
if let Some(ex_trait_ref) = obj.principal() {
// Here, we are passing the type `usize` as a
// placeholder value with the function
Expand All @@ -198,41 +190,44 @@ fn insert_required_predicates_to_be_wf<'tcx>(
}
}

ty::Alias(ty::Projection, obj) => {
// This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
// explicit predicates as well.
ty::Alias(ty::Projection, alias) => {
// This corresponds to a type like `<() as Trait<'a, T>>::Type`.
// We only use the explicit predicates of the trait but
// not the ones of the associated type itself.
debug!("Projection");
check_explicit_predicates(
tcx,
tcx.parent(obj.def_id),
obj.args,
tcx.parent(alias.def_id),
alias.args,
required_predicates,
explicit_map,
None,
);
}

// FIXME(inherent_associated_types): Handle this case properly.
// FIXME(inherent_associated_types): Use the explicit predicates from the parent impl.
ty::Alias(ty::Inherent, _) => {}

_ => {}
}
}
}

/// We also have to check the explicit predicates
/// declared on the type.
/// Check the explicit predicates declared on the type.
///
/// ### Example
///
/// ```ignore (illustrative)
/// struct Foo<'a, T> {
/// field1: Bar<T>
/// struct Outer<'a, T> {
/// field: Inner<T>,
/// }
///
/// struct Bar<U> where U: 'static, U: Foo {
/// ...
/// struct Inner<U> where U: 'static, U: Outer {
/// // ...
/// }
/// ```
/// Here, we should fetch the explicit predicates, which
/// will give us `U: 'static` and `U: Foo`. The latter we
/// will give us `U: 'static` and `U: Outer`. The latter we
/// can ignore, but we will want to process `U: 'static`,
/// applying the substitution as above.
fn check_explicit_predicates<'tcx>(
Expand Down Expand Up @@ -303,3 +298,45 @@ fn check_explicit_predicates<'tcx>(
insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates);
}
}

/// Check the inferred predicates declared on the type.
///
/// ### Example
///
/// ```ignore (illustrative)
/// struct Outer<'a, T> {
/// outer: Inner<'a, T>,
/// }
///
/// struct Inner<'b, U> {
/// inner: &'b U,
/// }
/// ```
///
/// Here, when processing the type of field `outer`, we would request the
/// set of implicit predicates computed for `Inner` thus far. This will
/// initially come back empty, but in next round we will get `U: 'b`.
/// We then apply the substitution `['b => 'a, U => T]` and thus get the
/// requirement that `T: 'a` holds for `Outer`.
fn check_inferred_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
args: ty::GenericArgsRef<'tcx>,
global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
required_predicates: &mut RequiredPredicates<'tcx>,
) {
// Load the current set of inferred and explicit predicates from `global_inferred_outlives`
// and filter the ones that are `TypeOutlives`.

let Some(predicates) = global_inferred_outlives.get(&def_id) else {
return;
};

for (&predicate, &span) in predicates.as_ref().skip_binder() {
// `predicate` is `U: 'b` in the example above.
// So apply the substitution to get `T: 'a`.
let ty::OutlivesPredicate(arg, region) =
predicates.rebind(predicate).instantiate(tcx, args);
insert_outlives_predicate(tcx, arg, region, span, required_predicates);
}
}
8 changes: 6 additions & 2 deletions compiler/rustc_hir_analysis/src/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
let crate_map = tcx.inferred_outlives_crate(());
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
}
DefKind::TyAlias if tcx.type_alias_is_lazy(item_def_id) => {
let crate_map = tcx.inferred_outlives_crate(());
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
}
DefKind::AnonConst if tcx.features().generic_const_exprs => {
let id = tcx.local_def_id_to_hir_id(item_def_id);
if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
Expand All @@ -47,8 +51,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
}

fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
// Compute a map from each struct/enum/union S to the **explicit**
// outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
// Compute a map from each ADT (struct/enum/union) and lazy type alias to
// the **explicit** outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
// Typically there won't be many of these, except in older code where
// they were mandatory. Nonetheless, we have to ensure that every such
// predicate is satisfied, so they form a kind of base set of requirements
Expand Down
48 changes: 24 additions & 24 deletions tests/ui/associated-type-bounds/duplicate.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ LL | struct SI1<T: Iterator<Item: Copy, Item: Send>> {
| |
| `Item` bound here first

error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:255:40
|
LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
| ---------- ^^^^^^^^^^ re-bound here
| |
| `Item` bound here first

error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:257:44
|
LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
| ---------- ^^^^^^^^^^ re-bound here
| |
| `Item` bound here first

error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:259:43
|
LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
| ------------- ^^^^^^^^^^^^^ re-bound here
| |
| `Item` bound here first

error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:11:36
|
Expand Down Expand Up @@ -490,30 +514,6 @@ LL | Self: Iterator<Item: 'static, Item: 'static>,
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:255:40
|
LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
| ---------- ^^^^^^^^^^ re-bound here
| |
| `Item` bound here first

error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:257:44
|
LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
| ---------- ^^^^^^^^^^ re-bound here
| |
| `Item` bound here first

error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:259:43
|
LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
| ------------- ^^^^^^^^^^^^^ re-bound here
| |
| `Item` bound here first

error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:243:34
|
Expand Down
34 changes: 34 additions & 0 deletions tests/ui/lazy-type-alias/implied-outlives-bounds.neg.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
error: lifetime may not live long enough
--> $DIR/implied-outlives-bounds.rs:21:12
|
LL | fn env0<'any>() {
| ---- lifetime `'any` defined here
LL | let _: TypeOutlives<'static, &'any ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/implied-outlives-bounds.rs:26:12
|
LL | fn env1<'any>() {
| ---- lifetime `'any` defined here
LL | let _: RegionOutlives<'static, 'any>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/implied-outlives-bounds.rs:31:12
|
LL | fn env2<'any>() {
| ---- lifetime `'any` defined here
LL | let _: Outer0<'static, &'any ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/implied-outlives-bounds.rs:36:12
|
LL | fn env3<'any>() {
| ---- lifetime `'any` defined here
LL | let _: Outer1<'static, &'any ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`

error: aborting due to 4 previous errors

Loading