Skip to content
Closed
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
71 changes: 56 additions & 15 deletions compiler/rustc_borrowck/src/type_check/free_region_relations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use tracing::{debug, instrument};
use type_op::TypeOpOutput;

Expand Down Expand Up @@ -235,21 +235,38 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let mut normalized_inputs_and_output =
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
for ty in unnormalized_input_output_tys {
// FIXME(type_alias_impl_trait): This is a temporary fix for
// trait-system-refactor-initiative#159.
//
// We have to make sure that we don't look into opaque types in the signature
// when computing implied bounds as doing so results in implied bounds which
// are not checked by the caller.
//
// This current approach is only sufficient for RPIT(IT) and somewhat of a mess.
// Fixing this properly blocks stabilization of TAIT and RTN. See #160425 for
// more details.
let (param_env, ty) = if tcx.next_trait_solver_globally() {
ty::set_opaques_to_rigid(tcx, (self.infcx.param_env, ty))
} else {
(self.infcx.param_env, ty)
};

debug!("build: input_or_output={:?}", ty);
// We add implied bounds from both the unnormalized and normalized ty.
// See issue #87748
let constraints_unnorm = self.add_implied_bounds(ty, span);
let constraints_unnorm = self.add_implied_bounds(param_env, ty, span);
if let Some(c) = constraints_unnorm {
constraints.push(c)
}
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
.infcx
.fully_perform(Normalize { value: ty::Unnormalized::new_wip(ty) }, span)
.unwrap_or_else(|guar| TypeOpOutput {
output: Ty::new_error(self.infcx.tcx, guar),
constraints: None,
error_info: None,
});
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } =
param_env
.and(Normalize { value: ty::Unnormalized::new_wip(ty) })
.fully_perform(self.infcx, self.infcx.root_def_id, span)
.unwrap_or_else(|guar| TypeOpOutput {
output: Ty::new_error(tcx, guar),
constraints: None,
error_info: None,
});
if let Some(c) = constraints_normalize {
constraints.push(c)
}
Expand All @@ -276,12 +293,33 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// ```
// Both &Self::Bar and &() are WF
if ty != norm_ty {
let constraints_norm = self.add_implied_bounds(norm_ty, span);
let constraints_norm = self.add_implied_bounds(param_env, norm_ty, span);
if let Some(c) = constraints_norm {
constraints.push(c)
}
}

// FIXME(type_alias_impl_trait): Part of the above fix. While we don't want to
// normalize opaque types for implied bounds, we do want to normalize them for
// the actual signature.
let norm_ty = if tcx.next_trait_solver_globally() && norm_ty.has_opaque_types() {
let norm_ty = ty::set_aliases_to_non_rigid(tcx, norm_ty);
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
.infcx
.fully_perform(Normalize { value: norm_ty }, span)
.unwrap_or_else(|guar| TypeOpOutput {
output: Ty::new_error(tcx, guar),
constraints: None,
error_info: None,
});
if let Some(c) = constraints_normalize {
constraints.push(c)
}
norm_ty
} else {
norm_ty
};

normalized_inputs_and_output.push(norm_ty);
}

Expand Down Expand Up @@ -309,7 +347,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {

// We currently add implied bounds from the normalized ty only.
// This is more conservative and matches wfcheck behavior.
let c = self.add_implied_bounds(norm_ty, span);
let c = self.add_implied_bounds(self.infcx.param_env, norm_ty, span);
constraints.extend(c);
}
}
Expand Down Expand Up @@ -377,12 +415,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn add_implied_bounds(
&mut self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
let TypeOpOutput { output: bounds, constraints, .. } = self
.infcx
.fully_perform(type_op::ImpliedOutlivesBounds { ty }, span)
// FIXME(type_alias_impl_trait): This should use the `param_env` of the `InferCtxt`,
// however we currently sometimes set the RPITIT opaque as rigid to avoid trait-system-refactor-initiative#159.
let TypeOpOutput { output: bounds, constraints, .. } = param_env
.and(type_op::ImpliedOutlivesBounds { ty })
.fully_perform(self.infcx, self.infcx.root_def_id, span)
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
.ok()?;
debug!(?bounds, ?constraints);
Expand Down
32 changes: 25 additions & 7 deletions compiler/rustc_type_ir/src/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,13 @@ where
ty::Unnormalized::new(folded)
}

pub fn set_opaques_to_rigid<I: Interner, T>(cx: I, value: T) -> T
where
T: TypeFoldable<I>,
{
set_aliases_rigidness_with_mode(cx, value, RigidnessFoldMode::OpaqueToRigid)
}

pub fn set_opaques_to_non_rigid<I: Interner, T>(cx: I, value: T) -> ty::Unnormalized<I, T>
where
T: TypeFoldable<I>,
Expand Down Expand Up @@ -607,6 +614,7 @@ enum RigidnessFoldMode {
AllToRigid,
AllToNonRigid,
TypeToRigid,
OpaqueToRigid,
OpaqueToNonRigid,
}

Expand All @@ -619,6 +627,7 @@ impl RigidnessFoldMode {
v.has_non_rigid_aliases()
&& v.has_type_flags(ty::TypeFlags::HAS_ALIAS - ty::TypeFlags::HAS_CONST_ALIAS)
}
RigidnessFoldMode::OpaqueToRigid => v.has_non_rigid_aliases() && v.has_opaque_types(),
RigidnessFoldMode::OpaqueToNonRigid => v.has_rigid_aliases() && v.has_opaque_types(),
}
}
Expand Down Expand Up @@ -650,16 +659,23 @@ impl<I: Interner> TypeFolder<I> for RigidnessFolder<I> {
let alias_ty = alias_ty.fold_with(self);
match self.mode {
RigidnessFoldMode::AllToRigid | RigidnessFoldMode::TypeToRigid => {
I::Ty::new_alias(self.cx(), ty::IsRigid::Yes, alias_ty)
I::Ty::new_alias(self.cx, ty::IsRigid::Yes, alias_ty)
}
RigidnessFoldMode::AllToNonRigid => {
I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty)
I::Ty::new_alias(self.cx, ty::IsRigid::No, alias_ty)
}
RigidnessFoldMode::OpaqueToRigid => {
if let ty::AliasTyKind::Opaque { .. } = alias_ty.kind {
I::Ty::new_alias(self.cx, ty::IsRigid::Yes, alias_ty)
} else {
I::Ty::new_alias(self.cx, is_rigid, alias_ty)
}
}
RigidnessFoldMode::OpaqueToNonRigid => {
if let ty::AliasTyKind::Opaque { .. } = alias_ty.kind {
I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty)
I::Ty::new_alias(self.cx, ty::IsRigid::No, alias_ty)
} else {
I::Ty::new_alias(self.cx(), is_rigid, alias_ty)
I::Ty::new_alias(self.cx, is_rigid, alias_ty)
}
}
}
Expand All @@ -681,10 +697,12 @@ impl<I: Interner> TypeFolder<I> for RigidnessFolder<I> {
I::Const::new_alias(self.cx, ty::IsRigid::Yes, alias_const)
}
RigidnessFoldMode::AllToNonRigid => {
I::Const::new_alias(self.cx(), ty::IsRigid::No, alias_const)
I::Const::new_alias(self.cx, ty::IsRigid::No, alias_const)
}
RigidnessFoldMode::OpaqueToNonRigid | RigidnessFoldMode::TypeToRigid => {
I::Const::new_alias(self.cx(), is_rigid, alias_const)
RigidnessFoldMode::OpaqueToRigid
| RigidnessFoldMode::OpaqueToNonRigid
| RigidnessFoldMode::TypeToRigid => {
I::Const::new_alias(self.cx, is_rigid, alias_const)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
error: lifetime may not live long enough
--> $DIR/wf-check-hidden-type.rs:14:5
--> $DIR/wf-check-hidden-type.rs:21:5
|
LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL |
LL | None::<&'_ &'_ ()>
| ^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/impl-trait/wf-check-hidden-type.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: lifetime may not live long enough
--> $DIR/wf-check-hidden-type.rs:19:1
|
LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
| ^^^^^^^^--^^--^^^^^^^^^^^^^^^^^^^^^^^^^^
| | | |
| | | lifetime `'b` defined here
| | lifetime `'a` defined here
| requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`

error: aborting due to 1 previous error

11 changes: 9 additions & 2 deletions tests/ui/impl-trait/wf-check-hidden-type.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
//! Regression test for #114728.
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

//! Regression test for #114728. This also catched
//! trait-system-refactor-initiative#159 with the new
//! solver.

trait Extend<'a, 'b> {
fn extend(self, _: &'a str) -> &'b str;
Expand All @@ -11,7 +17,8 @@ impl<'a, 'b> Extend<'a, 'b> for Option<&'b &'a ()> {
}

fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
None::<&'_ &'_ ()> //~ ERROR lifetime may not live long enough
//[next]~^ ERROR lifetime may not live long enough
None::<&'_ &'_ ()> //[current]~ ERROR lifetime may not live long enough
}

fn main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/implied-bounds-leak-hidden-ty-2.rs:18:5
|
LL | into_y(t)
| ^^^^^^^^^
| |
| the parameter type `T` must be valid for the static lifetime...
| ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | fn wat<T: 'static>(t: T) -> impl Sized + 'static {
| +++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0310`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/implied-bounds-leak-hidden-ty-2.rs:16:1
|
LL | fn wat<T>(t: T) -> impl Sized + 'static {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the parameter type `T` must be valid for the static lifetime...
| ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | fn wat<T: 'static>(t: T) -> impl Sized + 'static {
| +++++++++

error[E0310]: the parameter type `T` may not live long enough
--> $DIR/implied-bounds-leak-hidden-ty-2.rs:18:5
|
LL | into_y(t)
| ^^^^^^^^^
| |
| the parameter type `T` must be valid for the static lifetime...
| ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | fn wat<T: 'static>(t: T) -> impl Sized + 'static {
| +++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0310`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

// Regression test for trait-system-refactor-initiative#159. We need to make sure
// that computing the implied assumptions of `wat` does not look into the hidden
// type `impl Sized`, as doing so adds a `T: 'static` implied bound which
// its caller does not have to prove.

fn into_y<T>(t: T) -> impl Sized
where
T: 'static,
{
t
}
fn wat<T>(t: T) -> impl Sized + 'static {
//[next]~^ ERROR the parameter type `T` may not live long enough
into_y(t) //~ ERROR the parameter type `T` may not live long enough
}

fn leak<T>(t: &T) -> &'static T {
*(&wat(t) as &dyn std::any::Any).downcast_ref().unwrap()
}

fn main() {
let buf = leak(&vec![vec![1]]);
dbg!(buf[0][0]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
error[E0310]: the associated type `<T as Trait>::Assoc` may not live long enough
--> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:5
|
LL | (Box::new(x), Outlives::<'static, <T as Trait>::Assoc>(None))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the associated type `<T as Trait>::Assoc` must be valid for the static lifetime...
| ...so that the type `<T as Trait>::Assoc` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | fn foo<T: Trait>(x: <T as Trait>::Assoc) -> (Box<dyn Any>, impl Sized) where <T as Trait>::Assoc: 'static {
| ++++++++++++++++++++++++++++++++++

error[E0310]: the associated type `<T as Trait>::Assoc` may not live long enough
--> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:6
|
LL | (Box::new(x), Outlives::<'static, <T as Trait>::Assoc>(None))
| ^^^^^^^^^^^
| |
| the associated type `<T as Trait>::Assoc` must be valid for the static lifetime...
| ...so that the type `<T as Trait>::Assoc` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | fn foo<T: Trait>(x: <T as Trait>::Assoc) -> (Box<dyn Any>, impl Sized) where <T as Trait>::Assoc: 'static {
| ++++++++++++++++++++++++++++++++++

error[E0310]: the associated type `<T as Trait>::Assoc` may not live long enough
--> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:6
|
LL | (Box::new(x), Outlives::<'static, <T as Trait>::Assoc>(None))
| ^^^^^^^^^^^
| |
| the associated type `<T as Trait>::Assoc` must be valid for the static lifetime...
| ...so that the type `<T as Trait>::Assoc` will meet its required lifetime bounds
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider adding an explicit lifetime bound
|
LL | fn foo<T: Trait>(x: <T as Trait>::Assoc) -> (Box<dyn Any>, impl Sized) where <T as Trait>::Assoc: 'static {
| ++++++++++++++++++++++++++++++++++

error[E0310]: the associated type `<T as Trait>::Assoc` may not live long enough
--> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:19
|
LL | (Box::new(x), Outlives::<'static, <T as Trait>::Assoc>(None))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the associated type `<T as Trait>::Assoc` must be valid for the static lifetime...
| ...so that the type `<T as Trait>::Assoc` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | fn foo<T: Trait>(x: <T as Trait>::Assoc) -> (Box<dyn Any>, impl Sized) where <T as Trait>::Assoc: 'static {
| ++++++++++++++++++++++++++++++++++

error[E0310]: the associated type `<T as Trait>::Assoc` may not live long enough
--> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:19
|
LL | (Box::new(x), Outlives::<'static, <T as Trait>::Assoc>(None))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the associated type `<T as Trait>::Assoc` must be valid for the static lifetime...
| ...so that the type `<T as Trait>::Assoc` will meet its required lifetime bounds
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider adding an explicit lifetime bound
|
LL | fn foo<T: Trait>(x: <T as Trait>::Assoc) -> (Box<dyn Any>, impl Sized) where <T as Trait>::Assoc: 'static {
| ++++++++++++++++++++++++++++++++++

error: aborting due to 5 previous errors

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